summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2017-04-15 23:45:51 +0200
committermanuel <manuel@mausz.at>2017-04-15 23:45:51 +0200
commit3e08b2a584461fa6df8d68ef6b99b080a21d3957 (patch)
tree6ba1d38b66b544c0b7a976b07ffb4ff72ef5b98d
parent3fbad518be91ec031c0bbbc487c01bdc069e8b9f (diff)
downloadarduino-3e08b2a584461fa6df8d68ef6b99b080a21d3957.tar.gz
arduino-3e08b2a584461fa6df8d68ef6b99b080a21d3957.tar.bz2
arduino-3e08b2a584461fa6df8d68ef6b99b080a21d3957.zip
oliver/ledstripe
-rw-r--r--oliver/lr_stripes/lr_stripes.ino369
1 files changed, 369 insertions, 0 deletions
diff --git a/oliver/lr_stripes/lr_stripes.ino b/oliver/lr_stripes/lr_stripes.ino
new file mode 100644
index 0000000..11563c0
--- /dev/null
+++ b/oliver/lr_stripes/lr_stripes.ino
@@ -0,0 +1,369 @@
1#include <ESP8266mDNS.h>
2#include <ArduinoOTA.h>
3#include <PubSubClient.h>
4#include <WiFiManager.h>
5#include <Bounce2.h>
6#include "secrets.h"
7
8const char* autoconf_ssid = AUTOCONF_SSID; //AP name for WiFi setup AP which your ESP will open when not able to connect to other WiFi
9const char* autoconf_pwd = AUTOCONF_PASSWORD; // AP password so noone else can connect to the ESP in case your router fails
10const char* mqtt_server = "192.168.0.10"; //MQTT Server IP, your home MQTT server eg Mosquitto on RPi, or some public MQTT
11const int mqtt_port = 1883; //MQTT Server PORT, default is 1883 but can be anything.
12
13const char* mqtt_pingall_sub = "home/pingall";
14const char* mqtt_pingall_pub = "home/pingall/response";
15
16#define MQTT_BASE "home/livingroom/ledstripe"
17const char* mqtt_device_boot = MQTT_BASE "/device";
18
19enum sensor_type : uint8_t
20{
21 SENSOR_RELAY = (1u << 0),
22 SENSOR_DIMMER = (1u << 1),
23 SENSOR_BUTTON = (1u << 2),
24};
25
26struct sensor_t
27{
28 uint8_t type;
29 struct
30 {
31 uint8_t pin; // relay pin
32 const char *mqtt_sub;
33 const char *mqtt_pub;
34 } relay;
35 struct
36 {
37 uint8_t pin; // push button pin
38 Bounce bounce;
39 } button;
40 struct
41 {
42 uint8_t pin; // dimmer pin
43 uint8_t level; // current dim level (0 to 100)
44 const char *mqtt_sub;
45 const char *mqtt_pub;
46 } dimmer;
47};
48
49struct sensor_t sensors[] = {
50 {
51 .type = SENSOR_RELAY | SENSOR_BUTTON | SENSOR_DIMMER,
52 .relay = {
53 .pin = D5,
54 .mqtt_sub = MQTT_BASE,
55 .mqtt_pub = MQTT_BASE "/status"
56 },
57 .button = {
58 .pin = D0,
59 .bounce = Bounce(),
60 },
61 .dimmer = {
62 .pin = D8,
63 .level = 100,
64 .mqtt_sub = MQTT_BASE "/brightness",
65 .mqtt_pub = MQTT_BASE "/brightness/status"
66 },
67 }
68};
69
70//#define SAVE_RESTORE
71
72#define NUM(a) (sizeof(a) / sizeof(*a))
73
74#define RELAY_ON 1 // GPIO value to write to turn on attached relay
75#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
76
77#define DIMMER_FADE_DELAY 40 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
78
79WiFiClient espClient;
80PubSubClient client(espClient);
81char convBuffer[10];
82
83bool relayRead(struct sensor_t *sensor);
84void relayWrite(struct sensor_t *sensor, bool state, bool send_update=false);
85void flipRelay(struct sensor_t *sensor, bool send_update=false);
86void checkButtons(void);
87inline uint8_t pwmValue(uint8_t level);
88void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update=false);
89
90void setup()
91{
92 Serial.begin(115200);
93 pinMode(BUILTIN_LED, OUTPUT);
94 analogWriteRange(100);
95
96 // set relay pins to output mode + restore to last known state
97 for (uint8_t i = 0; i < NUM(sensors); i++)
98 {
99 struct sensor_t *sensor = &sensors[i];
100 if (sensor->type & SENSOR_RELAY)
101 {
102 pinMode(sensor->relay.pin, OUTPUT);
103#ifdef SAVE_RESTORE
104#error "not implemented"
105#else
106 digitalWrite(sensor->relay.pin, RELAY_OFF);
107#endif
108 }
109
110 if (sensor->type & SENSOR_DIMMER)
111 {
112 pinMode(sensor->dimmer.pin, OUTPUT);
113#ifdef SAVE_RESTORE
114#error "not implemented"
115#else
116 uint8_t level = sensor->dimmer.level;
117#endif
118 if ((sensor->type & SENSOR_RELAY) && !relayRead(sensor))
119 level = 0;
120 analogWrite(sensor->dimmer.pin, pwmValue(level));
121 }
122
123 if (sensor->type & SENSOR_BUTTON)
124 {
125 pinMode(sensor->button.pin, INPUT);
126 sensor->button.bounce.attach(sensor->button.pin);
127 }
128 }
129
130 WiFiManager wifiManager;
131 wifiManager.autoConnect(autoconf_ssid, autoconf_pwd);
132
133 setup_ota();
134
135 client.setServer(mqtt_server, mqtt_port);
136 client.setCallback(callback);
137
138 digitalWrite(BUILTIN_LED, HIGH); //Turn off led as default
139}
140
141void setup_ota()
142{
143 // Set OTA Password, and change it in platformio.ini
144 ArduinoOTA.setPassword(OTA_PASSWORD);
145 ArduinoOTA.onStart([]() {});
146 ArduinoOTA.onEnd([]() {});
147 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {});
148 ArduinoOTA.onError([](ota_error_t error)
149 {
150 if (error == OTA_AUTH_ERROR); // Auth failed
151 else if (error == OTA_BEGIN_ERROR); // Begin failed
152 else if (error == OTA_CONNECT_ERROR); // Connect failed
153 else if (error == OTA_RECEIVE_ERROR); // Receive failed
154 else if (error == OTA_END_ERROR); // End failed
155 });
156 ArduinoOTA.begin();
157}
158
159void reconnect()
160{
161 // Loop until we're reconnected
162 while (!client.connected())
163 {
164 // Create a random client ID
165 String clientId = "ESP8266Client-";
166 clientId += String(random(0xffff), HEX);
167
168 // Attempt to connect
169 if (client.connect(clientId.c_str()))
170 {
171 // Once connected, publish an announcement...
172 client.publish(mqtt_device_boot, "connected");
173 // ... and resubscribe
174 client.subscribe(mqtt_pingall_sub);
175
176 // publish states
177 for (uint8_t i = 0; i < NUM(sensors); i++)
178 {
179 struct sensor_t *sensor = &sensors[i];
180 if (sensor->type & SENSOR_RELAY)
181 {
182 Serial.println(sensor->relay.mqtt_sub);
183 client.subscribe(sensor->relay.mqtt_sub);
184 client.publish(sensor->relay.mqtt_pub, relayRead(sensor) ? "1" : "0",
185 true);
186 }
187
188 if (sensor->type & SENSOR_DIMMER)
189 {
190 Serial.println(sensor->dimmer.mqtt_sub);
191 client.subscribe(sensor->dimmer.mqtt_sub);
192 itoa(sensor->dimmer.level, convBuffer, 10);
193 client.publish(sensor->dimmer.mqtt_pub, convBuffer, true);
194 }
195 }
196 }
197 else
198 {
199 // Wait 5 seconds before retrying
200 delay(5000);
201 }
202 }
203}
204
205void callback(char* topic, byte* payload, unsigned int length)
206{
207 char c_payload[length];
208 memcpy(c_payload, payload, length);
209 c_payload[length] = '\0';
210
211 if (strcmp(topic, mqtt_pingall_sub) == 0)
212 {
213 blink();
214 client.publish(mqtt_pingall_pub,
215 "{\"livingroom_ledstrip\":\"connected\"}");
216 return;
217 }
218
219 for (uint8_t i = 0; i < NUM(sensors); i++)
220 {
221 struct sensor_t *sensor = &sensors[i];
222 if (sensor->type & SENSOR_RELAY
223 && length > 0
224 && strcmp(topic, sensor->relay.mqtt_sub) == 0)
225 {
226 blink();
227 relayWrite(sensor, payload[0] == '1', true);
228 return;
229 }
230
231 if (sensor->type & SENSOR_DIMMER
232 && length > 0
233 && strcmp(topic, sensor->dimmer.mqtt_sub) == 0)
234 {
235 blink();
236 uint8_t level = atoi((char *)payload);
237 fadeDimmer(sensor, (level > 100) ? 100 : level, true);
238 return;
239 }
240 }
241}
242
243void blink()
244{
245 //Blink on received MQTT message
246 digitalWrite(BUILTIN_LED, LOW);
247 delay(25);
248 digitalWrite(BUILTIN_LED, HIGH);
249}
250
251void loop()
252{
253 if (!client.connected())
254 reconnect();
255 client.loop();
256 ArduinoOTA.handle();
257 checkButtons();
258}
259
260bool relayRead(struct sensor_t *sensor)
261{
262 if (sensor->type & SENSOR_RELAY)
263 return digitalRead(sensor->relay.pin) == RELAY_ON;
264 return false;
265}
266
267void relayWrite(struct sensor_t *sensor, bool state, bool send_update)
268{
269 if (!(sensor->type & SENSOR_RELAY))
270 return;
271
272 Serial.print(F("Incoming change for relay: "));
273 Serial.print(sensor->relay.pin);
274 Serial.print(F(", New state: "));
275 Serial.println(state);
276
277 digitalWrite(sensor->relay.pin, state ? RELAY_ON : RELAY_OFF);
278
279 if (sensor->type & SENSOR_DIMMER)
280 analogWrite(sensor->dimmer.pin, state ? pwmValue(sensor->dimmer.level) : 0);
281
282#ifdef SAVE_RESTORE
283#error "not implemented"
284#endif
285
286 if (send_update)
287 client.publish(sensor->relay.mqtt_pub, state ? "1" : "0", true);
288}
289
290void flipRelay(struct sensor_t *sensor, bool send_update)
291{
292 relayWrite(sensor, relayRead(sensor) ? RELAY_OFF : RELAY_ON, send_update);
293}
294
295inline void checkButtons(void)
296{
297 for (uint8_t i = 0; i < NUM(sensors); i++)
298 {
299 struct sensor_t *sensor = &sensors[i];
300 if (sensor->type & SENSOR_BUTTON)
301 {
302 sensor->button.bounce.update();
303 if (sensor->button.bounce.fell())
304 flipRelay(sensor, true);
305 }
306 }
307}
308
309const uint8_t pwmtable[101] PROGMEM = {
310 // value below 0 turns of the power supply
311 0, 10, 10, 11, 11, 11, 11, 12, 12, 12,
312 13, 13, 13, 13, 14, 14, 14, 15, 15, 15,
313 16, 16, 17, 17, 17, 18, 18, 19, 19, 19,
314 20, 20, 21, 21, 22, 22, 23, 23, 24, 25,
315 25, 26, 26, 27, 28, 28, 29, 30, 30, 31,
316 32, 32, 33, 34, 35, 35, 36, 37, 38, 39,
317 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
318 50, 51, 52, 54, 55, 56, 58, 59, 60, 62,
319 63, 65, 66, 68, 69, 71, 72, 74, 76, 78,
320 79, 81, 83, 85, 87, 89, 91, 93, 95, 98,
321 100
322};
323
324inline uint8_t pwmValue(uint8_t level)
325{
326 //uint8_t lvl = 100 - (uint8_t)pgm_read_byte(&pwmtable[level]);
327 //return (lvl < 10) 10 : lvl;
328 //level = (level > 0 && level < 10) ? 10 : level;
329 //return 100 - level;
330 return 100 - (uint8_t)pgm_read_byte(&pwmtable[level]);
331}
332
333void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update)
334{
335 if (!(sensor->type & SENSOR_DIMMER))
336 return;
337 if (level > 100)
338 level = 100;
339
340 Serial.print(F("Incoming change for dimmer: "));
341 Serial.print(sensor->dimmer.pin);
342 Serial.print(F(", New level: "));
343 Serial.println(level);
344
345 if (level > 0 && sensor->type & SENSOR_RELAY && !relayRead(sensor))
346 relayWrite(sensor, RELAY_ON, send_update);
347
348 int delta = ((int8_t)(level - sensor->dimmer.level) < 0) ? -1 : 1;
349 while (sensor->dimmer.level != level)
350 {
351 sensor->dimmer.level += delta;
352 analogWrite(sensor->dimmer.pin, pwmValue(sensor->dimmer.level));
353 delay(DIMMER_FADE_DELAY);
354 }
355
356 if (level == 0 && sensor->type & SENSOR_RELAY && relayRead(sensor))
357 relayWrite(sensor, RELAY_OFF, send_update);
358
359#ifdef SAVE_RESTORE
360#error "not implemented"
361#endif
362
363 if (send_update)
364 {
365 itoa(level, convBuffer, 10);
366 client.publish(sensor->dimmer.mqtt_pub, convBuffer, true);
367 }
368}
369