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 | } |