So here is my project: I am working on a multi-sensor device which is also intended to control solid state relays.
As it stands, I am using TMP102 temperature sensors which report over the I2C protocol to an Arduino Due. w/ WiShield 1.0
The temperature data for two sensors is being sent via POST method to a PHP script on a colocated server.
The remote PHP script stores the incoming data in an SQL database which I then analyze using JpGraph & PHP.
This part is working just fine - I have been collecting temperature data for ~6mo now.
What I am struggling with is the following:
Getting control data from the remote server to control a solid state relay.
What I would like to do is use my SQL database to control the switch states (Boolean function, really).
I have written a PHP script that polls my database and returns the only following:
<switch name>,<switch state> (eg. |1,0)
I am using pipe ( | ) as a sort of index to parse the incoming GET request so that my code knows where to start looking for the actual control data.
I would like to make this scalable so that I could have say, 4 switches, all having their states returned with a single query of the SQL/PHP server.
So I need to somehow include the ability to intelligently parse multiple switch data.
Ie: sw1,1 .. sw2,0 .. sw3,1 .. etc
As it stands, if I make a text file (switch.php) with |1,0 in it, the switch get set to off, similarly if the text file contains only |1,1 the switch is turned on.
When I test my swtich.php using the SQL data, my web browser reports only: |1,0 or |1,1 but the Arduino does not control the switch accordingly.
I was hoping that an experienced coder could have a look at my source (below) and make suggestions / help me along my way.
I think that my problems are in the very last fuction in the code below, however, I am also open to critique of my general methods.
- Code: Select all
#include <WiServer.h>
#include <Wire.h>
// Wireless configuration parameters ----------------------------------------
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
unsigned char local_ip[] = {192,168,1,130}; // IP address of WiShield
unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"apnamehere"}; // max 32 bytes
unsigned char security_type = 2; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
const prog_char security_passphrase[] PROGMEM = {"appasswdhere"}; // max 64 characters
prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
uint8 ip[] = {111,222,333,444}; // obviously fake values ;)
POSTrequest sendData(ip, 80, "www.servername.here", "/project1/temp.php?", tempData); // post tempData to server
GETrequest getData(ip, 80, "www.servername.here", "/project1/switch.php"); // get switch states from server (ie: sw1,1 .. sw2,0 .. etc)
// Temperature sensor parameters --------------------------------------------
int ptrTemp = 0b00000000; // TMP102 register pointers
int ptrConf = 0b00000001;
int addr0 = 0b1001001; // ADD0 pin connection selects one of four possible addresses 1001001 = Vcc, 1001000 = gnd
int addr1 = 0b1001000;
int hightempmark = 0;
int lowtempmark = 100;
float temp0cal = 0; // calibration variable for sensor0
float temp1cal = 0; // calibration variable for sensor1
// Digital switching parameters ---------------------------------------------
int led = 6; // Indicator LED for sw0 - using PWM via analogWrite(led, 128) to avoid using a resistor
int sw1 = 0; // default switch state for sw0 set to off
// Misc. configuration parameters -------------------------------------------
int debug = 1; // if set to 1, multiple Serial.print outputs will be made
int ptr = 0, cntr = 0;
int indexFound = 0;
char* dataIn;
// Begin program space --------------------------------------------------------
void setup(){
serialInit(); // initialize serial interface & LCD output
I2Cinit(); // initialize the I2C network for temperature sensors
tempCal(); // cross-calibrate temperature sensor to the same temperature (greatest)
swInit(); // initialize digital switching parameters
wirelessInit(); // start WiFi connection
}
void loop(){
sendData.submit(); // submit temperature data for sensors using POSTrequest sendData in wireless configuration parameters
getData.submit(); // get switch state data using GETrequest getData in wireless configuration parameters
WiServer.server_task(); // have WiServer actually process the sendData.submit() and getData.submit() routines
}
void serialInit(){ // start up serial console at 9600 baud, and initialize serial LCD
Serial.begin(9600);
delay(100);
Serial.print(12, BYTE);
delay(5);
Serial.print(17, BYTE);
delay(5);
Serial.print(22, BYTE); // screen on, no blink
delay(5);
}
void I2Cinit(){ // start up the I2C interface, setting this host as mater unit
Wire.begin(); // join i2c bus (address optional for master)
// delay(100);
Serial.println();
Serial.println("Initializing I2C interface...");
Wire.beginTransmission(addr0); // select temperature register
Wire.send(ptrTemp);
Wire.endTransmission();
Wire.beginTransmission(addr1); // select temperature register
Wire.send(ptrTemp);
Wire.endTransmission();
Serial.println("DONE!");
Serial.println();
Serial.print("Using temperature sensors #1 (");
Serial.print(addr0, BIN);
Serial.print(") and #2 (");
Serial.print(addr1, BIN);
Serial.println(")");
}
void tempCal(){ // calibrate the temperature sensors to each other, using the higher value as the reference
int calCnt=0;
int calTotal = 50; // total number of sensor samplings to be done
int calDelay = 10; // delay between samplings (ms)
float temp0avg = 0;
float temp1avg = 0;
float temp0start = 0;
float temp1start = 0;
Serial.println();
Serial.println("Temperature Sensor Calibration In Progress:");
Serial.println("1% 50% 100%");
do { // take calTotal number of readings and find the average sensor values
Serial.print("|");
temp0avg = temp0avg + getTemp(0,0);
temp1avg = temp1avg + getTemp(1,0);
delay(calDelay);
calCnt++;
} while (calCnt < calTotal);
temp0avg = (temp0avg/calCnt);
temp1avg = (temp1avg/calCnt);
if (temp0avg > temp1avg) { temp0cal = temp0avg - temp1avg; }
if (temp0avg < temp1avg) { temp1cal = temp1avg - temp0avg; }
temp0start = getTemp(0,temp0cal);
temp1start = getTemp(1,temp1cal);
Serial.println();
Serial.println("DONE!");
Serial.println();
Serial.print("Initial temperature (sensor 0): ");
Serial.print(temp0start);
Serial.print(" calibrated by -");
Serial.print(temp0cal);
Serial.print(" with Tavg=");
Serial.println(temp0avg);
Serial.print("Initial temperature (sensor 1): ");
Serial.print(temp1start);
Serial.print(" calibrated by -");
Serial.print(temp1cal);
Serial.print(" with Tavg=");
Serial.println(temp1avg);
}
void swInit(){ // initialize digital switching routines, including testing the On/Off LED
pinMode(led, OUTPUT); // led pin set to 6 in global variables
pinMode(7, OUTPUT); // SW1 output
pinMode(3, OUTPUT); // SW2 output
digitalWrite(7, LOW); // make sure the digital output is low, ie switch off
digitalWrite(3, LOW); // make sure the digital output is low, ie switch off
Serial.println();
Serial.println("Testing digital output...");
Serial.println("LED On");
analogWrite(led, 128);
Serial.print("1..");
delay(1000);
Serial.print("2..");
delay(1000);
Serial.println("3..");
delay(1000);
Serial.println("LED Off");
analogWrite(led, 0);
}
void wirelessInit(){ // initialize the WiFi connection
Serial.println();
Serial.println("Initializing wireless connection...");
int start = millis(); // time the connection routine
WiServer.init(NULL); // disable the internal web server
WiServer.enableVerboseMode(false); // changed to false, do not provide verbose output
sendData.setReturnFunc(printData); // setup how the resulting data from the sendData routine is handled
getData.setReturnFunc(printData2); // setup how the resulting data from the getData routine is handled
Serial.println("DONE!");
Serial.print("Connection took: "); // output the results of the timer
int stop1 = ((millis() - start)*-1);
Serial.print(stop1/1000);
Serial.println(" seconds");
Serial.println();
}
void printData(char* data, int len){ // how the headers returned from sendData routine are handled
while (len-- > 0) {
// Serial.print(*(data++));
}
uip_close(); // disconnect from server - was commented out
}
void swSet(){ // should add (int sw) then use "sw" to controll the switch # - ie. make this function scalable
int sw = 0; // place holder, should be global or function passed variable
if (debug==1){ // if debugging is set, print this data via serial console
Serial.print(12, BYTE);
Serial.println("----------");
Serial.print(13, BYTE);
Serial.print("Sw: ");
Serial.print(sw);
Serial.print(13, BYTE);
Serial.print("Onoff: ");
Serial.print(sw1); // sw1 is a boolean (global) value for the state of switch 1, controlled by the SQL data
Serial.print(13, BYTE);
Serial.print(millis()/1000);
}
if (sw1==0) {
// Serial.println("Device 0 set to OFF");
analogWrite(led, 0); // if the bit is set, turn on the LED
digiOut(3,0);
}
if (sw1==1) {
// Serial.println("Device 0 set to ON");
analogWrite(led, 128); // if the bit is not set, turn off the LED
digiOut(3,1);
}
}
float getTemp(int sensor, float cal){ // poll sensor for temperature and subtract cal from its value and return the result
int addr = addr0;
if (sensor == 0) { addr = addr0; } // sensor #1
if (sensor == 1) { addr = addr1; } // sensor #2
Wire.requestFrom(addr, 2); // request temperature
byte byte1 = Wire.receive();
byte byte2 = Wire.receive();
// CALCULATING TEMPERATURES
int tempint = byte1 << 8; // shift first byte to high byte in an int
tempint = tempint | byte2; // or the second byte into the int
tempint = tempint >> 4; // right shift the int 4 bits per chip doc
float tempflt = float( tempint ) * .0625; // calculate actual temperature per chip doc
if (tempflt > hightempmark) {
hightempmark = tempflt;
}
if (tempflt < lowtempmark) {
lowtempmark = tempflt;
}
return tempflt-cal;
}
void tempData(){
float temp0 = 0, temp1 = 0;
temp0 = getTemp(0,temp0cal);
temp1 = getTemp(1,temp1cal);
if (debug==1){ // if debugging is set, print this data via serial console
Serial.println();
Serial.print("Reporting the following data: ");
Serial.print("temp0=");
Serial.print(temp0);
Serial.print(" & temp1=");
Serial.print(temp1);
Serial.println();
}
WiServer.print("temp0=");
WiServer.print(temp0);
WiServer.print("&temp1=");
WiServer.print(temp1);
}
void digiOut(int pin, int state){ // unused pins available to control swiches (via SSR, etc)
// unused pins include: 0,1,3,4,5,6,7
if (state==1) { digitalWrite(pin, HIGH); }
if (state==0) { digitalWrite(pin, LOW); }
}
void printData2(char* data, int len) { // how the headers returned from getData routine are handled
if (len > 0){
memset(dataIn, ' ', sizeof(dataIn)); // clear dataIn and initialize cleanly for length of data packet
for (int cntChar=0; cntChar < len; cntChar++) {
char chrIn = data[cntChar]; // gather data from data variable 1 char at a time
if (chrIn == '|') { // more advanced: if ((chrIn == '|') || (indexFound != 1))
dataIn[ptr] = chrIn; // set the first dataIn[0] to the current chrIn, post-increment ptr
ptr++;
indexFound = 1;
} // end of if (chrIn == '|')
if (indexFound == 1) {
sscanf(dataIn, "%[^,], %d", sw1); // ignore the switch name for now, just get the state (and hope it works)
Serial.println(onoff);
} // end of (indexFound == 1)
} // end of for (int cntChar=0; cntChar < len; cntChar++)
} // end of (len > 0)
// uip_close(); // disconnect from server - this causes data packet loss for some reason, ie. does not finish GET request
}
Edit: Here is a copy of my PHP backend of the switch.php for analyis also:
- Code: Select all
<?php
include ("db.php");
$sw = $_GET['sw'];
$today = date("Y-m-d");
if ($dbtable == "") $dbtable = "switches";
mysql_connect($host,$login,$passwd);
@mysql_select_db($dbname) or die( "Unable to connect to database");
$query = " SELECT *
FROM switches
";
$result = mysql_query($query);
$cnt = 0;
$cnt2 = 0;
while($row = mysql_fetch_row($result))
{
$switchIn[$cnt] = $row[0];
$stateIn[$cnt] = $row[1];
$dateIn[$cnt] = $row[2];
$cnt++;
}
mysql_free_result($result);
while($cnt2 < $cnt)
{
$dateInConv[$cnt2] = date("Y-m-d H:i:s",$dateIn[$cnt2]);
$cnt2++;
}
$cnt3=0;
while($cnt3 < $cnt)
{
echo "|";
echo $switchIn[$cnt3];
echo ",";
echo $stateIn[$cnt3];
$cnt3++;
} // example, outputs: |1,1
?>