Created
December 1, 2016 16:09
-
-
Save MZachmann/be7f140b5d40683e8a588246355eebbe to your computer and use it in GitHub Desktop.
Photon Source for REST Controller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// include the HttpClient code so we can send REST commands | |
#include "HttpClient.h" | |
// ----------------------------------------------- | |
// Defines | |
// ----------------------------------------------- | |
// turn this on to usb test | |
#define USE_DUMMY 0 | |
// for now hardcode IR and temperature sensors to a 4-count | |
#define num_sense 4 | |
// seconds between sending of new data | |
#define POLL_TIME 20 | |
// amount of temperature change to force sending | |
#define TEMPERATURE_MAX 100 | |
// some way to test a USB-connected with the latest software | |
#if USE_DUMMY | |
#define ROOM_NAME "DummyTest" | |
#define LOGGING 1 | |
#else | |
#define ROOM_NAME "Office" | |
#define LOGGING 0 | |
#endif | |
// ----------------------------------------------- | |
// Declaring the global variables. | |
// ----------------------------------------------- | |
int allowGet = 1; // for debugging, this lets us hit a key to start stuff up | |
// this is the value used to determine if we're a V1 board | |
int testTempRead = 1; // make this global so we can print it later in the loop | |
// Headers currently need to be set at init, useful for API keys etc. | |
http_header_t httpHeaders[] = { | |
// { "Content-Type", "application/json" }, | |
// { "Accept" , "application/json" }, | |
{ "Accept" , "*/*"}, | |
{ NULL, NULL } // NOTE: Always terminate headers will NULL | |
}; | |
http_request_t httpRequest; | |
http_response_t httpResponse; | |
// Define the pins we're going to call pinMode on | |
int led2 = D7; // This one is the built-in tiny one to the right of the USB jack | |
//V1 definitions | |
int temps[num_sense] = { A2, A3, A4, A5 }; | |
int irs[num_sense] = { D1, D2, D3, D4 }; | |
// autosense what we have available | |
bool hasInitialed = false; | |
bool tempAvails[num_sense] = { false,false,false,false}; | |
bool irAvails[num_sense] = {false,false,false,false}; | |
// readings | |
int readTemps[num_sense] = { 0,0,0,0}; | |
bool readIrs[num_sense] = {false,false,false,false}; | |
int lastTimeRead = Time.now(); | |
bool isV1 = false; // is this a version 1 board (no A0 input and D1,D2,D3,D4 digitals) | |
// ----------------------------------------------- | |
// Setup code | |
// This routine runs only once upon reset | |
// ----------------------------------------------- | |
void setup() | |
{ | |
#if LOGGING | |
Serial.begin(19200); // Open serial over USB. | |
#endif | |
// Figure out of this is a V1 board | |
// If it's a V2 board then A0 will be populated with a thermistor | |
pinMode( A0, INPUT_PULLDOWN); // per the doc this shouldn't be necessary since analogRead sets it to AN_INPUT | |
testTempRead = analogRead(A0); // per my test this will read < 1000 the first time due to the pulldown request (?) | |
// after we do the pulldown request. it will then end up around 1100 per my testing | |
isV1 = (testTempRead < 1400); // a V1 board will not have a thermistor at A0 and so it will read <1000 usually | |
if(isV1) // !!! Warning this test is Photon dependent | |
{ | |
pinMode( A0, INPUT_PULLDOWN); // per the doc this shouldn't be necessary since analogRead sets it to AN_INPUT | |
} | |
// this gives better accuracy | |
setADCSampleTime(ADC_SampleTime_84Cycles); | |
// set the arrays based on V1 or V2 | |
if(!isV1) | |
{ | |
int newTemps[num_sense] = { A0, A3, A4, A5 }; | |
int newIrs[num_sense] = { D0, D1, D2, D3 }; | |
for(int i=0; i<num_sense; i++) | |
{ | |
temps[i] = newTemps[i]; | |
irs[i] = newIrs[i]; | |
} | |
} | |
// Initialize the IR input pins | |
// It's important you do this here, inside the setup() function rather than outside it or in the loop function. | |
for(int i=0; i<num_sense; i++) | |
{ | |
pinMode( irs[i], INPUT_PULLDOWN); | |
} | |
pinMode(led2, OUTPUT); // Turn on the D7 led as output to show IR status | |
// determine which temperature sensors we have. Any sensor will read less than 3800 for sure | |
for(int i=0; i<num_sense; i++) | |
{ | |
readTemps[i] = analogRead(temps[i]); | |
tempAvails[i] = (readTemps[i] < 3800); | |
} | |
// determine which IR sensors are connected, it's not clear how to do this since it seems to be open collector | |
// so the following code just doesn't work | |
// for(int i=0; i<num_sense; i++) | |
// { | |
// pinMode( irs[i], INPUT_PULLUP); | |
// bool isIr = (digitalRead(irs[i]) == HIGH); | |
// pinMode( irs[i], INPUT_PULLDOWN); | |
// irAvails[i] = (digitalRead(irs[i]) == HIGH) == isIr; // has it flipped with different pullup/down? | |
// } | |
} | |
// ----------------------------------------------- | |
// Is the network ready? | |
// ----------------------------------------------- | |
bool isNetworkReady() | |
{ | |
bool isValidNet = true; | |
IPAddress gate = WiFi.gatewayIP(); | |
if( ! WiFi.ready()) | |
{ | |
isValidNet = false; | |
#if LOGGING | |
Serial.print("Not wifi ready."); | |
#endif | |
} | |
else if(gate[0] != 192 || gate[1] != 168 || gate[2] != 0) | |
{ | |
// the gateway is always in our local 192.168.0.xxx network | |
isValidNet = false; | |
#if LOGGING | |
Serial.print("Invalid gateway: "); | |
Serial.println(gate); | |
#endif | |
} | |
#if LOGGING | |
if(isValidNet) | |
{ | |
Serial.print("Wifi address: "); | |
Serial.println(WiFi.localIP()); | |
Serial.print("Subnet mask: "); | |
Serial.println(WiFi.subnetMask()); | |
// Prints out the gateway IP over Serial. | |
Serial.print("Gateway IP: "); | |
Serial.println(WiFi.gatewayIP()); | |
} | |
#endif | |
return isValidNet; | |
} | |
// ----------------------------------------------- | |
// convert a bool array to 1,0 strings | |
// ----------------------------------------------- | |
String joinBools(bool theArray[]) | |
{ | |
String allBool = ""; | |
for(int i=0; i<num_sense; i++) | |
{ | |
if(i) | |
{ | |
allBool = allBool + ","; | |
} | |
allBool = allBool + (theArray[i] ? "1" : "0"); | |
} | |
return allBool; | |
} | |
// ----------------------------------------------- | |
// convert an int array to ,d strings | |
// ----------------------------------------------- | |
String joinInts(int theArray[]) | |
{ | |
String allInts = ""; | |
for(int i=0; i<num_sense; i++) | |
{ | |
if(i) | |
{ | |
allInts = allInts + ","; | |
} | |
allInts = allInts + String(theArray[i]); | |
} | |
return allInts; | |
} | |
// ----------------------------------------------- | |
// figure out what sensors we have and send that information to the server | |
// ----------------------------------------------- | |
String getDefinition() | |
{ | |
String room = ROOM_NAME; | |
String setDef = "/sensor/rest/SetDef?Name="+room; | |
setDef = setDef + "&Temps="; | |
setDef = setDef + joinBools(tempAvails); | |
setDef = setDef + "&IRs="; | |
setDef = setDef + joinBools(irAvails); | |
setDef = setDef + "&Ver="; | |
setDef = setDef + (isV1 ? "1" : "2"); | |
#if LOGGING | |
Serial.println("set definition== "+setDef); | |
#endif | |
return setDef; | |
} | |
// send and http request | |
void SendHttpPath(String path) | |
{ | |
// Request path and body can be set at runtime or at setup. | |
httpRequest.ip = IPAddress(192,168,0,92); | |
httpRequest.port = 80; // http default port using nginx forwarding | |
httpRequest.path = path; | |
httpRequest.hostname = NULL; | |
#if LOGGING | |
Serial.print("Path: "); | |
Serial.print("192.168.0.92"); | |
Serial.println(path); | |
#endif | |
#if !USE_DUMMY | |
HttpClient httpClient; | |
httpClient.get(httpRequest, httpResponse, httpHeaders); | |
#endif | |
} | |
// This routine gets called repeatedly, like once every 5-15 milliseconds. | |
// Spark firmware interleaves background CPU activity associated with WiFi + Cloud activity with your code. | |
// Make sure none of your code delays or blocks for too long (like more than 5 seconds), or weird things can happen. | |
void loop() | |
{ | |
bool sendIrs = false; // turn on the IR led? | |
bool forceSend = false; // if we have a change in status, push it immediately | |
int newTemps[num_sense]; | |
// read the sensors | |
for(int i=0; i<num_sense; i++) | |
{ | |
// we can't save the new temperatures because it may 'slowly' increase | |
// don't bother with sensors not hooked up, this may increase analog accuracy also | |
if(tempAvails[i]) | |
newTemps[i] = analogRead(temps[i]); | |
else | |
newTemps[i] = readTemps[i]; | |
int diff = abs(newTemps[i] - readTemps[i]); | |
if(diff > TEMPERATURE_MAX) | |
{ | |
forceSend = true; | |
} | |
bool newIR = (digitalRead(irs[i]) == HIGH); | |
if(newIR != readIrs[i]) | |
{ | |
forceSend = true; | |
} | |
readIrs[i] = newIR; | |
// if it has gone high, say so to LED | |
if(readIrs[i]) | |
sendIrs = true; | |
delayMicroseconds(100); // for the a/d i think | |
} | |
// only broadcast every few seconds | |
int newTime = Time.now(); | |
if((!forceSend) && ((newTime - lastTimeRead) < POLL_TIME) ) | |
{ | |
return; | |
} | |
lastTimeRead = newTime; | |
// flip the LED on if we have an IR high | |
digitalWrite(led2, sendIrs ? HIGH : LOW); | |
// now update the read temperatures | |
for(int i=0; i<num_sense; i++) | |
{ | |
readTemps[i] = newTemps[i]; | |
} | |
#if LOGGING | |
if(isV1) | |
{ | |
Serial.print("This is a V1 board reading: "); | |
} | |
else | |
{ | |
Serial.print("This is a V2 board reading: "); | |
} | |
Serial.println(testTempRead); | |
Serial.print("forceSend is "); | |
Serial.println(forceSend ? "on" : "off"); | |
#endif | |
bool isValidNet = isNetworkReady(); | |
// Send the current status REST command | |
if(isValidNet && (allowGet > 0)) | |
{ | |
// send the definition to the server once | |
if(! hasInitialed) | |
{ | |
hasInitialed = true; | |
// room definition | |
String setDef = getDefinition(); | |
SendHttpPath(setDef); | |
} | |
String tempStr = "Temps="; | |
tempStr += joinInts(readTemps); | |
String irStr = "IR="; | |
irStr += joinBools(readIrs); | |
// send current status | |
String room = ROOM_NAME; | |
String path = "/sensor/rest/SetRoom?Name=" + room + "&" + tempStr + "&" + irStr; | |
SendHttpPath(path); | |
} | |
#if LOGGING | |
if(Serial.available()) | |
{ | |
int rd = Serial.read(); | |
switch(rd) | |
{ | |
case 'n' : | |
allowGet = 0; | |
break; | |
case 'y' : | |
allowGet = 5; | |
break; | |
default : | |
break; | |
} | |
} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment