SHOW:
|
|
- or go back to the newest paste.
| 1 | /*********************************************************************************************************** | |
| 2 | Variables used for turning a pin high/low, depending on temperature | |
| 3 | ***********************************************************************************************************/ | |
| 4 | #define relayPin 7 // Set what pin the relay is connected to | |
| 5 | #define relayInvert 0 // Set to 1 to invert the function of the relay | |
| 6 | ||
| 7 | float targetTemp = 23.0; // Target temperature | |
| 8 | float targetHyst = 0.1; // Hysteresis determinig how much over and under target temp it should trigger | |
| 9 | ||
| 10 | ||
| 11 | /*********************************************************************************************************** | |
| 12 | Variables used for reading the TMP36 temperature sensor | |
| 13 | ***********************************************************************************************************/ | |
| 14 | #define TMP36pin A0 | |
| 15 | #define readTMP36trot 500 // Time in milliseconds between temperature readings | |
| 16 | char tempStr[16]; // Holding the result in the json api reply | |
| 17 | ||
| 18 | /*********************************************************************************************************** | |
| 19 | Variables used for averaging temperature readings | |
| 20 | The temperature can be accessed by opening https://api.spark.io/v1/devices/{device id}/temperature?access_token={access token}
| |
| 21 | ***********************************************************************************************************/ | |
| 22 | #define tempArraySize 20 // Size of the arry holding values for averaging | |
| 23 | double temps[tempArraySize]; // Arry holding temperature readings | |
| 24 | double temperature = 0; // Current average temperature | |
| 25 | int idx = 0; // Index of where we are in the array | |
| 26 | ||
| 27 | ||
| 28 | /*********************************************************************************************************** | |
| 29 | Only used temporarily until Spark.publish(); can run from inside a function called by Spark.function(); | |
| 30 | ***********************************************************************************************************/ | |
| 31 | char sendPublishMessage[128]; | |
| 32 | bool sendPublishActive = false; | |
| 33 | void sendPublish() | |
| 34 | {
| |
| 35 | if (sendPublishActive) | |
| 36 | {
| |
| 37 | sendPublishActive = false; | |
| 38 | Spark.publish("debug", sendPublishMessage);
| |
| 39 | } | |
| 40 | } | |
| 41 | ||
| 42 | ||
| 43 | void setup() | |
| 44 | {
| |
| 45 | pinMode(relayPin, OUTPUT); // Set pin for the relay to output | |
| 46 | Spark.variable("temperature", &tempStr, STRING); // Register variable so it can be accessed with the api later
| |
| 47 | ||
| 48 | Spark.function("SETPINS", handlePinCommand);
| |
| 49 | } | |
| 50 | ||
| 51 | ||
| 52 | void loop() | |
| 53 | {
| |
| 54 | nodeSync(); // When last sync was and sync if needed | |
| 55 | ||
| 56 | cyclePins(); // Run through the tables and check if we got any pulses remaining on any pin | |
| 57 | ||
| 58 | readTMP36(); // Read from the temperature sensor and set the temperature variable | |
| 59 | sprintf(tempStr, "%4.3f", temperature); // Set the result we are going to reply with when asked by the api (returning temperature with two decimals) | |
| 60 | ||
| 61 | handleRelay(); // Check temperature and determine if relay should be pulled or released | |
| 62 | ||
| 63 | sendPublish(); // Check if we got any messages pending to be published | |
| 64 | } | |
| 65 | ||
| 66 | /*********************************************************************************************************** | |
| 67 | Determine if the pin should be HIGH or LOW depending on temperature and hysteresis | |
| 68 | ***********************************************************************************************************/ | |
| 69 | bool relayState = false; | |
| 70 | void handleRelay() | |
| 71 | {
| |
| 72 | char sendPublishMessage[128]; | |
| 73 | if (temperature < (targetTemp-targetHyst)) // If the temperature is below our target temperature-hysteresis then... | |
| 74 | {
| |
| 75 | digitalWrite(relayPin, relayInvert?LOW:HIGH); // Set pin high, or low if function is inverted | |
| 76 | ||
| 77 | if (!relayState) | |
| 78 | {
| |
| 79 | relayState = true; | |
| 80 | Spark.publish("relay", "1");
| |
| 81 | } | |
| 82 | } | |
| 83 | else if (temperature > targetTemp+targetHyst) // If the temperature is ablove target temperature+hysteresis then.. | |
| 84 | {
| |
| 85 | digitalWrite(relayPin, relayInvert?HIGH:LOW); // Set pin to low, or high if function is inverted | |
| 86 | ||
| 87 | if (relayState) | |
| 88 | {
| |
| 89 | relayState = false; | |
| 90 | Spark.publish("relay", "0");
| |
| 91 | } | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | ||
| 96 | /*********************************************************************************************************** | |
| 97 | Read from the TMP36 sensor, calculate themperature and average tmperature | |
| 98 | ***********************************************************************************************************/ | |
| 99 | unsigned long readTMP36last = 0; // Holding time of when temperature was last checked | |
| 100 | void readTMP36() // Function for reading from the sensor | |
| 101 | {
| |
| 102 | unsigned int now = millis(); // Set the current time (from when the controller was powered on) | |
| 103 | ||
| 104 | if (now - readTMP36last < readTMP36trot) return; // If less than 500ms (default) has passed, just stop here and return to loop() | |
| 105 | ||
| 106 | readTMP36last = now; // More than 500ms (default) has passed, store the time we are reading at so we know when to do it again | |
| 107 | ||
| 108 | temps[idx] = ((((analogRead(TMP36pin)*3.3)/4095.0)-0.5)*100.0); // Check analog input and calculate the temperature | |
| 109 | ||
| 110 | if (++idx >= tempArraySize) idx = 0; // Add one to the array index, and check that we dont go above its size, if we do, set index to 0 | |
| 111 | ||
| 112 | double total = 0; // Used to hold total value of the array | |
| 113 | for(int i=0; i < tempArraySize; i++) // Run through the array holding the temperatures | |
| 114 | {
| |
| 115 | total += temps[i]; // Add each temperature in the array to the total | |
| 116 | } | |
| 117 | temperature = total / tempArraySize; // Set temperature variable to total temperature, divided by the array size, so we get an average temperature | |
| 118 | } | |
| 119 | ||
| 120 | ||
| 121 | /*********************************************************************************************************** | |
| 122 | Hold info about how many pulses/steps each pin should do, the delay between them, | |
| 123 | when it last pulsed, and how long a pulse should be | |
| 124 | ***********************************************************************************************************/ | |
| 125 | int stepsLeft[8]; // Array to store how many times it should flash the pin | |
| 126 | int stepDelay[8]; // Array to store how long a delay there should be between the pin state changing | |
| 127 | unsigned long lastStep[8]; // Array to store when the pin was changed last | |
| 128 | int pulseLength[8] = {50, 50, 50, 50, 50, 50, 50, 200}; // Array holding pulse length for each pin, so each pin can have a different pulse length
| |
| 129 | ||
| 130 | void cyclePins() | |
| 131 | {
| |
| 132 | for (int i = 0; i <= 8; i++) // Run through the arrays to see if any pin should be changed | |
| 133 | {
| |
| 134 | unsigned long now = millis(); | |
| 135 | ||
| 136 | if (stepsLeft[i] > 0) // Do we have to do any steps on this pin? | |
| 137 | {
| |
| 138 | if (now - lastStep[i] >= stepDelay[i]) // Calculate if we are at, or passed the set delay time between pulses | |
| 139 | {
| |
| 140 | lastStep[i] = now; // Set when we set the pin HIGH, so we can calculate when to set it LOW again | |
| 141 | digitalWrite(i, HIGH); // Set pin to HIGH | |
| 142 | stepsLeft[i]--; // Remove one step | |
| 143 | } | |
| 144 | } | |
| 145 | ||
| 146 | if (now - lastStep[i] >= pulseLength[i] && stepsLeft[i] >= 0) // Check if pin has been HIGH long enough and if we are above -1 steps left | |
| 147 | {
| |
| 148 | if (stepsLeft[i] == 0) stepsLeft[i] = -1; // Set steps left to -1 so we don't get in here again | |
| 149 | ||
| 150 | digitalWrite(i, LOW); // Set pin to LOW | |
| 151 | } | |
| 152 | } | |
| 153 | } | |
| 154 | ||
| 155 | /*********************************************************************************************************** | |
| 156 | Receiving the command for the pins and filling the arrays in the above section accordingly | |
| 157 | ***********************************************************************************************************/ | |
| 158 | int handlePinCommand(String command) | |
| 159 | {
| |
| 160 | int pinNum = 0, pinState = 0, pinDelay = 0; | |
| 161 | ||
| 162 | char * params = new char[command.length() + 1]; | |
| 163 | strcpy(params, command.c_str()); | |
| 164 | ||
| 165 | char * p = strtok(params, "-"); | |
| 166 | ||
| 167 | int commandStep = 0; | |
| 168 | while (p != NULL) | |
| 169 | {
| |
| 170 | //get the values for | |
| 171 | if (commandStep == 0) | |
| 172 | {
| |
| 173 | pinNum = atoi(p); | |
| 174 | } | |
| 175 | else if (commandStep == 1) | |
| 176 | {
| |
| 177 | pinState = atoi(p); | |
| 178 | } | |
| 179 | else if (commandStep == 2) | |
| 180 | {
| |
| 181 | pinDelay = atoi(p); | |
| 182 | if (pinDelay < pulseLength[pinNum]) pinDelay = pulseLength[pinNum] + 5; // Delay between each pulse can't be less than the pulse length | |
| 183 | } | |
| 184 | ||
| 185 | commandStep++; | |
| 186 | p = strtok(NULL, "-"); | |
| 187 | } | |
| 188 | ||
| 189 | pinMode(pinNum, OUTPUT); //Set pin to OUTPUT | |
| 190 | ||
| 191 | if (stepsLeft[pinNum]) // We gott a new command while doing a number of pulses | |
| 192 | {
| |
| 193 | stepsLeft[pinNum] = 0; | |
| 194 | stepDelay[pinNum] = 0; | |
| 195 | lastStep[pinNum] = 0; | |
| 196 | digitalWrite(pinNum, LOW); | |
| 197 | } | |
| 198 | ||
| 199 | if (pinDelay > 0) | |
| 200 | {
| |
| 201 | stepsLeft[pinNum] = pinState; //Store how many times the pin should flash, it is changing state for each pass, so it should be done twice for 1 on/off cycle | |
| 202 | stepDelay[pinNum] = pinDelay; //Store the delay between pin changes | |
| 203 | lastStep[pinNum] = 0; //Set the last time it changed to 0 so it will happen on next loop | |
| 204 | ||
| 205 | sprintf(sendPublishMessage,"Pin: %d - Flashes: %d - Delay: %d",pinNum,pinState,pinDelay); | |
| 206 | } | |
| 207 | else | |
| 208 | {
| |
| 209 | stepsLeft[pinNum] = -1; // Set steps left to -1 so cyclePins() will leave it alone | |
| 210 | digitalWrite(pinNum, pinState?HIGH:LOW); // Set the pin defined earlier | |
| 211 | sprintf(sendPublishMessage,"Pin: %d - State: %d", pinNum, pinState); | |
| 212 | } | |
| 213 | ||
| 214 | sendPublishActive = true; | |
| 215 | ||
| 216 | return 1; | |
| 217 | } | |
| 218 | ||
| 219 | /*********************************************************************************************************** | |
| 220 | Doing synchronization with the database to make sure controller and database is set the same | |
| 221 | ***********************************************************************************************************/ | |
| 222 | TCPClient client; | |
| 223 | ||
| 224 | unsigned long syncStart = 0; | |
| 225 | unsigned long lastSync = 0; | |
| 226 | unsigned long nextSyncIn = 3600000; // Store how many milliseconds until we sync again | |
| 227 | ||
| 228 | int syncState = 1; // 1 = Need to sync now / 2 = Connected to server / 3 = Client is available / 4 = Reading from web server | |
| 229 | - | if ((millis() - lastSync < nextSyncIn && lastSync != 0) && millis() >= lastSync) return; //Only check once every hour, unless we havent checked yet, or if time since overflow of millis is less than last time we checked |
| 229 | + | |
| 230 | const char server[] = "www.server.com"; | |
| 231 | - | syncStart = millis(); |
| 231 | + | |
| 232 | bool webRead = false; | |
| 233 | - | unsigned long tic = millis(); |
| 233 | + | bool isTime = true; |
| 234 | - | char send2PublishMessage[128]; |
| 234 | + | String webString = String(15); |
| 235 | ||
| 236 | - | RGB.control(true); |
| 236 | + | |
| 237 | {
| |
| 238 | - | const char server[] = "www.server.com"; |
| 238 | + | if (syncState == 0) // Check if it is time to sync |
| 239 | {
| |
| 240 | - | if (sendGetRequest (server)) |
| 240 | + | if (millis() - lastSync >= nextSyncIn) syncState = 1; //Only check once every hour, unless we havent checked yet, or if time since overflow of millis is less than last time we checked |
| 241 | - | {
|
| 241 | + | |
| 242 | - | while (!client.available()) |
| 242 | + | else if (syncState == 1) // Need to sync now |
| 243 | {
| |
| 244 | lastSync = millis(); // We read all to the end of the command line, forget the time we reached that point | |
| 245 | ||
| 246 | webString = ""; | |
| 247 | ||
| 248 | char buf[256]; | |
| 249 | - | bool webRead = false; |
| 249 | + | |
| 250 | - | bool isTime = true; |
| 250 | + | if (client.connect (server, 80)) |
| 251 | - | String webString = String(15); |
| 251 | + | |
| 252 | RGB.color(255, 0, 0); | |
| 253 | sprintf (buf, "GET /sync.php?spark=%s HTTP/1.1\r\n", Spark.deviceID().c_str()); | |
| 254 | - | while (client.available()) |
| 254 | + | client.print (buf); |
| 255 | sprintf (buf, "Connection: close\r\nHost: %s\r\n\r\n", server); | |
| 256 | client.print (buf); | |
| 257 | client.flush(); | |
| 258 | syncState = 2; | |
| 259 | } | |
| 260 | } | |
| 261 | else if (syncState == 2) // Connected to the web server, waiting for it to reply | |
| 262 | {
| |
| 263 | syncStart = millis(); | |
| 264 | ||
| 265 | RGB.control(true); | |
| 266 | ||
| 267 | if (client.available()) | |
| 268 | {
| |
| 269 | - | sprintf(send2PublishMessage,"Next synchronization in: %i seconds", (nextSyncIn/1000)); |
| 269 | + | syncState = 3; |
| 270 | - | Spark.publish("debug", send2PublishMessage);
|
| 270 | + | |
| 271 | } | |
| 272 | } | |
| 273 | else if (syncState == 3) // Web server replied, read what was replied | |
| 274 | {
| |
| 275 | RGB.color(255, 165, 0); | |
| 276 | ||
| 277 | if(client.available()) | |
| 278 | {
| |
| 279 | char c = client.read(); | |
| 280 | ||
| 281 | if (webRead && (c == ',' || c == '>')) // , = command seperator > = no more commands | |
| 282 | - | webString.concat(c); |
| 282 | + | |
| 283 | if (isTime) | |
| 284 | {
| |
| 285 | isTime = false; | |
| 286 | ||
| 287 | char * inString = new char[webString.length() + 1]; | |
| 288 | - | lastSync = millis(); // We read all to the end of the command line, forget the time we reached that point |
| 288 | + | |
| 289 | nextSyncIn = atoi(inString); | |
| 290 | - | break; |
| 290 | + | |
| 291 | } | |
| 292 | else | |
| 293 | {
| |
| 294 | handlePinCommand(webString); //Send the string with commands to the function to execute it | |
| 295 | } | |
| 296 | webString = ""; //Empty string so it is ready for a new command | |
| 297 | } | |
| 298 | else | |
| 299 | {
| |
| 300 | if (webRead) // webRead is set to true when we encounter the start of commands character | |
| 301 | {
| |
| 302 | webString.concat(c); | |
| 303 | } | |
| 304 | - | break; |
| 304 | + | |
| 305 | ||
| 306 | if (c == '>') // > = end of commands | |
| 307 | {
| |
| 308 | webString = ""; | |
| 309 | syncState = 4; | |
| 310 | } | |
| 311 | - | sendPublish(); |
| 311 | + | |
| 312 | if (c == '<') // < = start of commands | |
| 313 | - | unsigned long toc = millis(); |
| 313 | + | |
| 314 | - | sprintf(send2PublishMessage,"Synchronization took : %ims", (toc-tic)); |
| 314 | + | |
| 315 | - | Spark.publish("debug", send2PublishMessage);
|
| 315 | + | |
| 316 | ||
| 317 | - | RGB.control(false); |
| 317 | + | |
| 318 | if (millis() - syncStart > 5000) // If synchronization takes more than 5 seconds, abort and try again in 60 seconds | |
| 319 | {
| |
| 320 | - | char buf[256]; |
| 320 | + | |
| 321 | - | int sendGetRequest (const char *server) |
| 321 | + | |
| 322 | syncState = 4; | |
| 323 | - | if (client.connect (server, 80)) |
| 323 | + | |
| 324 | } | |
| 325 | - | RGB.color(255, 0, 0); |
| 325 | + | else |
| 326 | - | sprintf (buf, "GET /sync.php?spark=%s HTTP/1.1\r\n", Spark.deviceID().c_str()); |
| 326 | + | |
| 327 | - | client.print (buf); |
| 327 | + | syncState = 4; |
| 328 | - | sprintf (buf, "Connection: close\r\nHost: %s\r\n\r\n", server); |
| 328 | + | |
| 329 | - | client.print (buf); |
| 329 | + | |
| 330 | - | client.flush(); |
| 330 | + | else if (syncState == 4) // Done with the web server, stop client and set state to check the time again |
| 331 | - | return 1; |
| 331 | + | |
| 332 | client.stop(); | |
| 333 | - | return 0; |
| 333 | + | |
| 334 | sendPublish(); | |
| 335 | ||
| 336 | RGB.control(false); | |
| 337 | syncState = 0; | |
| 338 | } | |
| 339 | } |