summaryrefslogtreecommitdiffstats
path: root/tv_light/src/tv_light.ino
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2020-01-01 15:32:00 +0100
committermanuel <manuel@mausz.at>2020-01-01 15:32:00 +0100
commit18535b811be94ebb8103dcef5bf2f07e9bd8ad8e (patch)
tree8468db947de601d55d849bfc8f562a1e3e2c67f5 /tv_light/src/tv_light.ino
parent39078df17a067a2838e019f535f58c626f386852 (diff)
downloadarduino-18535b811be94ebb8103dcef5bf2f07e9bd8ad8e.tar.gz
arduino-18535b811be94ebb8103dcef5bf2f07e9bd8ad8e.tar.bz2
arduino-18535b811be94ebb8103dcef5bf2f07e9bd8ad8e.zip
update tv_light
Diffstat (limited to 'tv_light/src/tv_light.ino')
-rw-r--r--tv_light/src/tv_light.ino339
1 files changed, 339 insertions, 0 deletions
diff --git a/tv_light/src/tv_light.ino b/tv_light/src/tv_light.ino
new file mode 100644
index 0000000..492069d
--- /dev/null
+++ b/tv_light/src/tv_light.ino
@@ -0,0 +1,339 @@
1/**
2 * The MySensors Arduino library handles the wireless radio link and protocol
3 * between your home built sensors/actuators and HA controller of choice.
4 * The sensors forms a self healing radio network with optional repeaters. Each
5 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
6 * network topology allowing messages to be routed to nodes.
7 */
8
9// Enable debug prints to serial monitor
10//#define MY_DEBUG
11
12// configure radio
13#define MY_RADIO_RFM69
14
15/** @brief RFM69 frequency to use (RF69_433MHZ for 433MHz, RF69_868MHZ for 868MHz or RF69_915MHZ for 915MHz). */
16#define MY_RFM69_FREQUENCY RF69_868MHZ
17
18/** @brief Enable this if you're running the RFM69HW model. */
19#define MY_IS_RFM69HW
20
21/** @brief RFM69 Network ID. Use the same for all nodes that will talk to each other. */
22#define MY_RFM69_NETWORKID 1
23
24/** @brief Node id defaults to AUTO (tries to fetch id from controller). */
25#define MY_NODE_ID 2
26
27/** @brief If set, transport traffic is unmonitored and GW connection is optional */
28#define MY_TRANSPORT_DONT_CARE_MODE
29
30/** @brief Node parent defaults to AUTO (tries to find a parent automatically). */
31#define MY_PARENT_NODE_ID 0
32
33/** @brief The user-defined AES key to use for EEPROM personalization */
34#include "aes_key.h"
35
36// Enable repeater functionality for this node
37//#define MY_REPEATER_FEATURE
38
39/** @brief Enables RFM69 automatic transmit power control class. */
40//#define MY_RFM69_ATC
41
42#ifdef MY_AES_KEY
43/** @brief enables RFM69 encryption */
44#define MY_RFM69_ENABLE_ENCRYPTION
45#endif
46
47#include <Arduino.h>
48#include <MySensors.h>
49#include <avr/pgmspace.h>
50
51enum sensor_type : uint8_t
52{
53 SENSOR_RELAY = (1u << 0),
54 SENSOR_DIMMER = (1u << 1),
55 SENSOR_BUTTON = (1u << 2),
56};
57
58struct sensor_t
59{
60 uint8_t id;
61 uint8_t type;
62 struct
63 {
64 uint8_t pin; // relay pin
65 } relay;
66 struct
67 {
68 uint8_t pin; // dimmer pin
69 uint16_t level; // current dim level (0 to 100)
70 } dimmer;
71};
72
73struct sensor_t sensors[] = {
74 {
75 .id = 0,
76 .type = SENSOR_RELAY,
77 .relay = { .pin = 4 },
78 },
79 {
80 .id = 1,
81 .type = SENSOR_RELAY | SENSOR_DIMMER,
82 //.type = SENSOR_RELAY,
83 .relay = { .pin = 5 },
84 .dimmer = { .pin = 6, .level = 100 },
85 },
86};
87
88//#define SAVE_RESTORE
89
90#define NUM(a) (sizeof(a) / sizeof(*a))
91
92#define RELAY_ON 1 // GPIO value to write to turn on attached relay
93#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
94
95#define DIMMER_FADE_DELAY 40 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
96
97#define TEMP_SENSOR_ID 254
98#define TEMP_READ_INTERVAL 1000L // read temp every 1 sec
99#define TEMP_N_READS_MSG 60*60 // force temp message every n reads
100#define TEMP_OFFSET 0
101
102MyMessage msg(0, V_STATUS);
103
104inline void checkTemperature(void);
105bool relayRead(struct sensor_t *sensor);
106void relayWrite(struct sensor_t *sensor, bool state, bool send_update=false);
107void flipRelay(struct sensor_t *sensor, bool send_update=false);
108inline uint8_t pwmValue(uint8_t level);
109void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update=false);
110
111void before()
112{
113 // set relay pins to output mode + restore to last known state
114 for (uint8_t i = 0; i < NUM(sensors); i++)
115 {
116 struct sensor_t *sensor = &sensors[i];
117 if (sensor->type & SENSOR_RELAY)
118 {
119 pinMode(sensor->relay.pin, OUTPUT);
120#ifdef SAVE_RESTORE
121 digitalWrite(sensor->relay.pin, loadState(sensor->id) ? RELAY_ON : RELAY_OFF);
122#else
123 digitalWrite(sensor->relay.pin, RELAY_OFF);
124#endif
125 }
126
127 if (sensor->type & SENSOR_DIMMER)
128 {
129 pinMode(sensor->dimmer.pin, OUTPUT);
130#ifdef SAVE_RESTORE
131 uint8_t level = loadState(NUM(sensors) + sensor->id;
132#else
133 uint8_t level = sensor->dimmer.level;
134#endif
135 if ((sensor->type & SENSOR_RELAY) && !relayRead(sensor))
136 level = 0;
137 analogWrite(sensor->dimmer.pin, pwmValue(level));
138 }
139 }
140
141#ifdef MY_AES_KEY
142 const uint8_t user_aes_key[16] = { MY_AES_KEY };
143 uint8_t cur_aes_key[16];
144 hwReadConfigBlock((void*)&cur_aes_key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, sizeof(cur_aes_key));
145 if (memcmp(&user_aes_key, &cur_aes_key, 16) != 0)
146 {
147 hwWriteConfigBlock((void*)user_aes_key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, sizeof(user_aes_key));
148 debug(PSTR("AES key written\n"));
149 }
150#endif
151}
152
153void setup()
154{
155#ifdef MY_IS_RFM69HW
156 _radio.setHighPower(true);
157#endif
158#ifdef MY_RFM69_ATC
159 _radio.enableAutoPower(-70);
160 debug(PSTR("ATC enabled\n"));
161#endif
162}
163
164void presentation()
165{
166 sendSketchInfo("TVLight", "1.0");
167
168 // register all sensors to gw (they will be created as child devices)
169 for (uint8_t i = 0; i < NUM(sensors); i++)
170 {
171 struct sensor_t *sensor = &sensors[i];
172 if (sensor->type & SENSOR_DIMMER)
173 present(sensor->id, S_DIMMER);
174 else if (sensor->type & SENSOR_RELAY || sensor->type & SENSOR_BUTTON)
175 present(sensor->id, S_BINARY);
176 }
177
178#if TEMP_SENSOR_ID >= 0
179 present(TEMP_SENSOR_ID, S_TEMP);
180#endif
181}
182
183void loop()
184{
185 //TODO maybe call _radio.rcCalibration() all 1000x changes?
186#if TEMP_SENSOR_ID >= 0
187 checkTemperature();
188#endif
189}
190
191inline void checkTemperature(void)
192{
193 static unsigned long lastTempUpdate = millis();
194 static unsigned int numTempUpdates = 0;
195 static float lastTemp = 0;
196 static MyMessage msgTemp(TEMP_SENSOR_ID, V_TEMP);
197
198 unsigned long now = millis();
199 if (now - lastTempUpdate > TEMP_READ_INTERVAL)
200 {
201 float temp = _radio.readTemperature() + TEMP_OFFSET;
202 lastTempUpdate = now;
203 if (isnan(temp))
204 Serial.println(F("Failed reading temperature"));
205 else if (abs(temp - lastTemp) >= 2 || numTempUpdates == TEMP_N_READS_MSG)
206 {
207 lastTemp = temp;
208 numTempUpdates = 0;
209 send(msgTemp.set(temp, 2));
210#ifdef MY_DEBUG
211 char str_temp[6];
212 dtostrf(temp, 4, 2, str_temp);
213 debug(PSTR("Temperature: %s °C\n"), str_temp);
214#endif
215 }
216 else
217 ++numTempUpdates;
218 }
219}
220
221void receive(const MyMessage &message)
222{
223 if (message.type == V_STATUS || message.type == V_PERCENTAGE)
224 {
225 uint8_t sensor_id = message.sensor;
226 if (sensor_id >= NUM(sensors))
227 {
228 Serial.print(F("Invalid sensor id:"));
229 Serial.println(sensor_id);
230 return;
231 }
232
233 struct sensor_t *sensor = &sensors[sensor_id];
234 if (message.type == V_STATUS && sensor->type & SENSOR_RELAY)
235 {
236 if (mGetCommand(message) == C_REQ)
237 send(msg.setType(V_STATUS).setSensor(sensor->id).set(relayRead(sensor)));
238 else if (mGetCommand(message) == C_SET)
239 relayWrite(sensor, message.getBool());
240 }
241 else if (message.type == V_PERCENTAGE && sensor->type & SENSOR_DIMMER)
242 {
243 if (mGetCommand(message) == C_REQ)
244 send(msg.setType(V_PERCENTAGE).setSensor(sensor->id).set(sensor->dimmer.level));
245 else if (mGetCommand(message) == C_SET)
246 {
247 uint16_t level = message.getUInt();
248 fadeDimmer(sensor, (level > 100) ? 100 : level);
249 }
250 }
251 }
252}
253
254bool relayRead(struct sensor_t *sensor)
255{
256 if (sensor->type & SENSOR_RELAY)
257 return digitalRead(sensor->relay.pin) == RELAY_ON;
258 return false;
259}
260
261void relayWrite(struct sensor_t *sensor, bool state, bool send_update)
262{
263 if (!(sensor->type & SENSOR_RELAY))
264 return;
265
266 Serial.print(F("Incoming change for relay: "));
267 Serial.print(sensor->relay.pin);
268 Serial.print(F(", New state: "));
269 Serial.println(state);
270
271 digitalWrite(sensor->relay.pin, state ? RELAY_ON : RELAY_OFF);
272
273 if (sensor->type & SENSOR_DIMMER)
274 analogWrite(sensor->dimmer.pin, state ? pwmValue(sensor->dimmer.level) : 0);
275
276#ifdef SAVE_RESTORE
277 saveState(sensor->id, state ? RELAY_ON : RELAY_OFF);
278#endif
279
280 if (send_update)
281 send(msg.setType(V_STATUS).setSensor(sensor->id).set(state));
282}
283
284void flipRelay(struct sensor_t *sensor, bool send_update)
285{
286 relayWrite(sensor, relayRead(sensor) ? RELAY_OFF : RELAY_ON, send_update);
287}
288
289inline uint8_t pwmValue(uint8_t level)
290{
291 static const uint8_t pwmtable[101] PROGMEM = {
292 0, 1, 1, 1, 1, 1, 1, 2, 2, 2,
293 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
294 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
295 5, 6, 6, 6, 7, 7, 8, 8, 8, 9,
296 9, 10, 11, 11, 12, 12, 13, 14, 15, 16,
297 16, 17, 18, 19, 20, 22, 23, 24, 25, 27,
298 28, 30, 32, 33, 35, 37, 39, 42, 44, 47,
299 49, 52, 55, 58, 61, 65, 68, 72, 76, 81,
300 85, 90, 95, 100, 106, 112, 118, 125, 132, 139,
301 147, 156, 164, 174, 183, 194, 205, 216, 228, 241,
302 255
303 };
304 return (uint8_t)pgm_read_byte(&pwmtable[level]);
305}
306
307void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update)
308{
309 if (!(sensor->type & SENSOR_DIMMER))
310 return;
311 if (level > 100)
312 level = 100;
313
314 Serial.print(F("Incoming change for dimmer: "));
315 Serial.print(sensor->dimmer.pin);
316 Serial.print(F(", New level: "));
317 Serial.println(level);
318
319 if (level > 0 && sensor->type & SENSOR_RELAY && !relayRead(sensor))
320 relayWrite(sensor, RELAY_ON);
321
322 int delta = ((int8_t)(level - sensor->dimmer.level) < 0) ? -1 : 1;
323 while (sensor->dimmer.level != level)
324 {
325 sensor->dimmer.level += delta;
326 analogWrite(sensor->dimmer.pin, pwmValue(sensor->dimmer.level));
327 delay(DIMMER_FADE_DELAY);
328 }
329
330 if (level == 0 && sensor->type & SENSOR_RELAY && relayRead(sensor))
331 relayWrite(sensor, RELAY_OFF);
332
333#ifdef SAVE_RESTORE
334 saveState(NUM(sensors) + sensor->id, level);
335#endif
336
337 if (send_update)
338 send(msg.setType(V_PERCENTAGE).setSensor(sensor->id).set(level));
339}