Ananyo Sen
Published © GPL3+

Stay at Home PI

Raspberry pi, at the center of the home will control everything from your doors to lights, can be controlled from an app.

IntermediateWork in progress79
Stay at Home PI

Things used in this project

Hardware components

Raspberry Pi 1 Model B+
Raspberry Pi 1 Model B+
×1

Software apps and online services

Microsoft Azure
Microsoft Azure
nodejs server running at http://stayhomep.azurewebsites.net, /get to get the current vars and /set?x=y to set vars

Story

Read more

Code

server.js

JavaScript
nodejs server running on azure to sync the variables,
var http = require('http');
var url = require('url');  //parse urls
var moment = require('moment');  //get time

var db = {};  //database object, actual db later

var port = process.env.PORT || 1337;    //from azure docs
http.createServer(function(req, res) {
	var path = url.parse(req.url).pathname;
  	res.writeHead(200, { 'Content-Type': 'text/plain' });
	if (path == "/get"){
		var now = moment();
		var formatted = now.format('YYYY-MM-DD;HH:mm:ss;Z');  
		db["time"] = formatted;  //setting timestamp
		var str = JSON.stringify(db);  // return json
		res.end(str);
	}  	 
	else if(path == "/set")
	{
		var queryData = url.parse(req.url, true).query;
		var keyss = Object.keys(queryData);  //get json from keys
		for (var iii = 0; iii < keyss.length; iii++)  
		{
			db[keyss[iii]] = queryData[keyss[iii]];	  //update keys in db
		}
		res.end("done");
	}
	else
	{
		res.end("not found, searching in /dev/null");  //tata
	}
}).listen(port);

raspi main

C/C++
this basically does all the stuff, compiled using wiringPi library, communicates with a web server, PIR sensor. bluetooth module and also the attiny and controls everything, basically the brain
WIP
#include <string>
#include <iostream>
#include <vector>

#include <cstdlib>

#include "wiringPi.h"
#include "wiringSerial.h"
#include "softPwm.h"
// #include "HttpRequest.h"
// #include "HttpException.h"
//url: stayhomepi
using namespace std;

const int PIR = 0, lightRPIN = 3, lightGPIN = 4, lightBPIN = 5;  //pins for pir sensor and rgb light pwm
const int lightThresh = 5, pwmRange = 50;
volatile bool lightOn = false;                 // volatile to prevent compiler optimizing
volatile bool pirActive = false;
volatile bool lowLight = false;
volatile int lightR = 0, lightG = 0, lightB = 0;

string comBT = "/dev/ttyAMA0"; //bt connected to onboard serial
string comAT = "/dev/ttyACM0"; // attiny connected via usb-serial converter
string lastSerAT = "", lastSerBT = "";  //to resend last serial command
int serialBT, serialAT;        //file descriptors returned by serialOpen

void setup();
void checkPIR();
void pirISR();
void changeLightIntensity(unsigned int r, unsigned int g, unsigned int b);
void checkSerAT();
void checkSerBT();
void parseStrData(string data);

void trim(string &data)
{
	//trim any whitespaces, newlines, tabs or carriage return from source string
	int pos = data.find_first_not_of(" \r\t\n");
	if(pos < 0)
	{
		data = "";
		return;
	}
	data = data.substr(pos);
	pos = data.find_last_not_of(" \r\n\t");
	data = data.substr(0, pos);
}

char* chr(string str)
{
	//convert std::string to char* using first pointer from string
	return &str[0];
}

int main(int argc, char const *argv[])
{
	setup();
	while(true)
	{
		checkPIR();
		checkSerAT();
		delay(10);	
	}
	return 0;
}

void setup()
{
	wiringPiSetup();  //initialise the GPIO pins
	pinMode(PIR, INPUT);  // pir pin as input
	wiringPiISR(PIR, INT_EDGE_BOTH, pirISR);  //register interrupt callback in case of rising or falling pulse
	serialBT = serialOpen(chr(comBT) , 9600);  // initialise serials
	serialAT = serialOpen(chr(comAT) , 9600);
	if(serialAT < 0)
	{
		cout << "unable to open "+comAT <<endl;    
		exit(-2);
	}
	if(serialBT < 0)
	{
		cout << "unable to open "+comBT <<endl;    
		exit(-2);
	}
	softPwmCreate(lightRPIN, lightR, pwmRange);  //initialise pwms
	softPwmCreate(lightGPIN, lightG, pwmRange);
	softPwmCreate(lightBPIN, lightB, pwmRange);
}

void checkPIR()
{
	if(pirActive && !lightOn)  // if movement detected and light is off
	{
		changeLightIntensity(50,50,50);  // turn on the lights with dim value
	}
}

void pirISR()
{
	delay(1);
	int pinStat = digitalRead(PIR);
	pirActive = pinStat;
}

void changeLightIntensity(unsigned int r, unsigned int g, unsigned int b)
{
	if(r > 250){  // maxvalue for soft_pwm is 50, 50*5 (you'll see) = 250
	    r = 250;
	}
	if(r > 250){
	    r = 250;
	}
	if(b > 250){
	    b = 250;
	}
	unsigned int mr = r/5, mg = g/5, mb = b/5;  // don't need finer resolution, just high frequency to prevent flickering
	if((mr + mg + mb) < lightThresh)
	{
		//set light master relay off
		lightOn = false;
		lastSerAT = "N";
	 	serialPuts(serialAT, chr(lastSerAT));
	}
	else
	{
		//set light master relay on and set pwm
		lightOn = true;
		lastSerAT = "P";
	 	serialPuts(serialAT, chr(lastSerAT));
	 	softPwmWrite(lightRPIN, mr);
	 	softPwmWrite(lightGPIN, mg);
	 	softPwmWrite(lightBPIN, mb);
	}
}

void checkSerAT()
{
	string temp = "";
	while(serialDataAvail(serialAT))
	{
		temp += static_cast<char>(serialGetchar(serialAT));
	}
	trim(temp);
	//consult attiny code for this
	if(temp == "NACK")
	{
		serialPuts(serialAT, chr(lastSerAT));
	}
	else if(temp == "high")
	{
		lightOn = true;
	}
	else if(temp == "low")
	{
		lightOn = false;
		lightR = lightG = lightB = 0;
	}
}

void checkSerBT()
{
	string temp = "";
	while(serialDataAvail(serialBT))
	{
		temp += static_cast<char>(serialGetchar(serialBT));
	}
	parseStrData(temp);
}

void parseStrData(string data)
{
	//trim it and separate the space delimited data to a vector of string
	trim(data);
	vector<string> strArr;
	int pos = data.find(' ');
	while(pos > 0)
	{
		strArr.push_back(data.substr(0, pos));
		data = data.substr(pos + 1);
		pos = data.find(' ');
	}
	strArr.push_back(data);
}

code to detect sound peaks using attiny85

C/C++
this code runs on an attiny85 perpetually and waits for two consecutive sound peaks in one second, if found, flips the master light switch and communicates with raspberry pi, attiny core from https://code.google.com/p/arduino-tiny/
//raspi does not have an ADC, offloading this tom attiny85
//attiny85 does not have a hardware serial to communicate with raspi
#include <SoftwareSerial.h>

//see pins_arduino.c from arduino-tiny core for pin mappings

const int micPin = 2; // output from the amp circuit at AIN2
const int relayPin = 1; // light master relay pin
const int tempPin = 3;  // lm35 temp sensor at AIN3

int maxVal = 0, minVal = 1023;
unsigned long long prevMill = 0;
bool outState = false;
SoftwareSerial mySerial(0, 2); //attiny pin 0 and 2 using softwareserial
#define LEVEL_THRESH 100

void setup()
{
    mySerial.begin(9600);
    pinMode(relayPin, OUTPUT);
}

void loop()
{
    if (mySerial.available())
    {
        // obey any command from the raspberry pi
        char c = mySerial.read();
        if (c == 'P')
        {
            lightOn();
        }
        else if (c == 'N')
        {
            lightOff();
        }
        else if(c == 'T')
        {
            mySerial.println(analogRead(tempPin));
        }
        else
        {
            //did not receive properly, send again?
            mySerial.println("NACK");
        }
    }

    if (calcDiff() > LEVEL_THRESH)
    {
        //detected one peak
        delay(100); // wait 0.1s so the previous sound does not trigger another peak
        prevMill = millis();
        while ((millis() - prevMill) < 1000)
        {
            //wait for one second for the next peak
            if (calcDiff() > LEVEL_THRESH)
            {
                //detected another peak in one second, flip the state
                if (outState)
                {
                    lightOff();
                    //wait 0.1s so the previous sound does not trigger another peak
                    break;
                }
                else
                {
                    lightOn();
                    //wait 0.1s so the previous sound does not trigger another peak
                    break;
                }
            }
        }
    }
}

void lightOn()
{
    outState = true;
    digitalWrite(relayPin, HIGH);
    mySerial.println("high");
    delay(100);
}

void lightOff()
{
    outState = false;
    digitalWrite(relayPin, LOW);
    mySerial.println("low");
    delay(100);
}

int calcDiff()
{
    //this function takes 100 consecutive values from amp and calculates diff between max and min values
    //8MHz is just enough to make it less error prone
    maxVal = 0;
    minVal = 1023;

    for (int iii = 0; iii < 100; iii++)
    {
        int senseData = analogRead(micPin);
        if (senseData > maxVal)
        {
            maxVal = senseData;
        }

        if (senseData < minVal)
        {
            minVal = senseData;
        }
    }
    mySerial.println(maxVal - minVal);
    return (maxVal - minVal);
}

Credits

Ananyo Sen

Ananyo Sen

1 project • 1 follower
Undergrad student, love things that tie up mechanics, electronics and computer science.

Comments