summaryrefslogtreecommitdiffstats
path: root/mysensors/couch_light
diff options
context:
space:
mode:
Diffstat (limited to 'mysensors/couch_light')
-rw-r--r--mysensors/couch_light/.gitignore5
-rw-r--r--mysensors/couch_light/platformio.ini26
-rw-r--r--mysensors/couch_light/src/main.cpp283
3 files changed, 314 insertions, 0 deletions
diff --git a/mysensors/couch_light/.gitignore b/mysensors/couch_light/.gitignore
new file mode 100644
index 0000000..89cc49c
--- /dev/null
+++ b/mysensors/couch_light/.gitignore
@@ -0,0 +1,5 @@
1.pio
2.vscode/.browse.c_cpp.db*
3.vscode/c_cpp_properties.json
4.vscode/launch.json
5.vscode/ipch
diff --git a/mysensors/couch_light/platformio.ini b/mysensors/couch_light/platformio.ini
new file mode 100644
index 0000000..d4ceb9b
--- /dev/null
+++ b/mysensors/couch_light/platformio.ini
@@ -0,0 +1,26 @@
1; PlatformIO Project Configuration File
2;
3; Build options: build flags, source filter, extra scripting
4; Upload options: custom port, speed and extra flags
5; Library options: dependencies, extra library storages
6;
7; Please visit documentation for the other options and examples
8; http://docs.platformio.org/en/stable/projectconf.html
9
10[platformio]
11default_envs = pro8MHzatmega328
12
13[env:miniatmega328]
14platform=atmelavr
15board=miniatmega328
16framework=arduino
17
18[env:pro8MHzatmega328]
19platform=atmelavr
20board=pro8MHzatmega328
21framework=arduino
22; minicore/optirun uses 38400 for 8MHz
23upload_speed=38400
24
25[platformio]
26lib_dir=/home/manuel/coding/Arduino/libraries
diff --git a/mysensors/couch_light/src/main.cpp b/mysensors/couch_light/src/main.cpp
new file mode 100644
index 0000000..b99381a
--- /dev/null
+++ b/mysensors/couch_light/src/main.cpp
@@ -0,0 +1,283 @@
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 1
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 <Bounce2.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; // push button pin
69 Bounce bounce;
70 } button;
71};
72
73struct sensor_t sensors[] = {
74 {
75 .id = 0,
76 .type = SENSOR_RELAY | SENSOR_BUTTON,
77 .relay = { .pin = 4 },
78 .button = { .pin = 6, .bounce = Bounce() },
79 },
80 {
81 .id = 1,
82 .type = SENSOR_RELAY | SENSOR_BUTTON,
83 .relay = { .pin = 5 },
84 .button = { .pin = 7, .bounce = Bounce() },
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 TEMP_SENSOR_ID 254
96#define TEMP_READ_INTERVAL 1000L // read temp every 1 sec
97#define TEMP_N_READS_MSG 60*60 // force temp message every n reads
98#define TEMP_OFFSET 0
99
100MyMessage msg(0, V_STATUS);
101
102inline void checkTemperature(void);
103bool relayRead(struct sensor_t *sensor);
104void relayWrite(struct sensor_t *sensor, bool state, bool send_update=false);
105void flipRelay(struct sensor_t *sensor, bool send_update=false);
106void checkButtons(void);
107
108void before()
109{
110 // set relay pins to output mode + restore to last known state
111 for (uint8_t i = 0; i < NUM(sensors); i++)
112 {
113 struct sensor_t *sensor = &sensors[i];
114 if (sensor->type & SENSOR_RELAY)
115 {
116 pinMode(sensor->relay.pin, OUTPUT);
117#ifdef SAVE_RESTORE
118 digitalWrite(sensor->relay.pin, loadState(sensor->id) ? RELAY_ON : RELAY_OFF);
119#else
120 digitalWrite(sensor->relay.pin, RELAY_OFF);
121#endif
122 }
123 }
124
125#ifdef MY_AES_KEY
126 const uint8_t user_aes_key[16] = { MY_AES_KEY };
127 uint8_t cur_aes_key[16];
128 hwReadConfigBlock((void*)&cur_aes_key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, sizeof(cur_aes_key));
129 if (memcmp(&user_aes_key, &cur_aes_key, 16) != 0)
130 {
131 hwWriteConfigBlock((void*)user_aes_key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, sizeof(user_aes_key));
132 debug(PSTR("AES key written\n"));
133 }
134#endif
135}
136
137void setup()
138{
139#ifdef MY_IS_RFM69HW
140 _radio.setHighPower(true);
141#endif
142#ifdef MY_RFM69_ATC
143 _radio.enableAutoPower(-70);
144 debug(PSTR("ATC enabled\n"));
145#endif
146
147 for (uint8_t i = 0; i < NUM(sensors); i++)
148 {
149 struct sensor_t *sensor = &sensors[i];
150 if (sensor->type & SENSOR_BUTTON)
151 {
152 pinMode(sensor->button.pin, INPUT_PULLUP);
153 sensor->button.bounce.attach(sensor->button.pin);
154 }
155 }
156}
157
158void presentation()
159{
160 sendSketchInfo("CouchLight", "1.0");
161
162 // register all sensors to gw (they will be created as child devices)
163 for (uint8_t i = 0; i < NUM(sensors); i++)
164 {
165 struct sensor_t *sensor = &sensors[i];
166 if (sensor->type & SENSOR_RELAY || sensor->type & SENSOR_BUTTON)
167 present(sensor->id, S_BINARY);
168 }
169
170#if TEMP_SENSOR_ID >= 0
171 present(TEMP_SENSOR_ID, S_TEMP);
172#endif
173}
174
175void loop()
176{
177 //TODO maybe call _radio.rcCalibration() all 1000x changes?
178 checkButtons();
179
180#if TEMP_SENSOR_ID >= 0
181 checkTemperature();
182#endif
183}
184
185inline void checkTemperature(void)
186{
187 static unsigned long lastTempUpdate = millis();
188 static unsigned int numTempUpdates = 0;
189 static float lastTemp = 0;
190 static MyMessage msgTemp(TEMP_SENSOR_ID, V_TEMP);
191
192 unsigned long now = millis();
193 if (now - lastTempUpdate > TEMP_READ_INTERVAL)
194 {
195 float temp = _radio.readTemperature() + TEMP_OFFSET;
196 lastTempUpdate = now;
197 if (isnan(temp))
198 Serial.println(F("Failed reading temperature"));
199 else if (abs(temp - lastTemp) >= 2 || numTempUpdates == TEMP_N_READS_MSG)
200 {
201 lastTemp = temp;
202 numTempUpdates = 0;
203 send(msgTemp.set(temp, 2));
204#ifdef MY_DEBUG
205 char str_temp[6];
206 dtostrf(temp, 4, 2, str_temp);
207 debug(PSTR("Temperature: %s °C\n"), str_temp);
208#endif
209 }
210 else
211 ++numTempUpdates;
212 }
213}
214
215void receive(const MyMessage &message)
216{
217 if (message.type == V_STATUS || message.type == V_PERCENTAGE)
218 {
219 uint8_t sensor_id = message.sensor;
220 if (sensor_id >= NUM(sensors))
221 {
222 Serial.print(F("Invalid sensor id:"));
223 Serial.println(sensor_id);
224 return;
225 }
226
227 struct sensor_t *sensor = &sensors[sensor_id];
228 if (message.type == V_STATUS && sensor->type & SENSOR_RELAY)
229 {
230 if (mGetCommand(message) == C_REQ)
231 send(msg.setType(V_STATUS).setSensor(sensor->id).set(relayRead(sensor)));
232 else if (mGetCommand(message) == C_SET)
233 relayWrite(sensor, message.getBool());
234 }
235 }
236}
237
238bool relayRead(struct sensor_t *sensor)
239{
240 if (sensor->type & SENSOR_RELAY)
241 return digitalRead(sensor->relay.pin) == RELAY_ON;
242 return false;
243}
244
245void relayWrite(struct sensor_t *sensor, bool state, bool send_update)
246{
247 if (!(sensor->type & SENSOR_RELAY))
248 return;
249
250 Serial.print(F("Incoming change for relay: "));
251 Serial.print(sensor->relay.pin);
252 Serial.print(F(", New state: "));
253 Serial.println(state);
254
255 digitalWrite(sensor->relay.pin, state ? RELAY_ON : RELAY_OFF);
256
257#ifdef SAVE_RESTORE
258 saveState(sensor->id, state ? RELAY_ON : RELAY_OFF);
259#endif
260
261 if (send_update)
262 send(msg.setType(V_STATUS).setSensor(sensor->id).set(state));
263}
264
265void flipRelay(struct sensor_t *sensor, bool send_update)
266{
267 relayWrite(sensor, relayRead(sensor) ? RELAY_OFF : RELAY_ON, send_update);
268}
269
270inline void checkButtons(void)
271{
272 for (uint8_t i = 0; i < NUM(sensors); i++)
273 {
274 struct sensor_t *sensor = &sensors[i];
275 if (sensor->type & SENSOR_BUTTON)
276 {
277 sensor->button.bounce.update();
278 if (sensor->button.bounce.fell())
279 flipRelay(sensor, true);
280 }
281 }
282}
283