-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMySensors-Efergy-e2.ino
295 lines (214 loc) · 5.98 KB
/
MySensors-Efergy-e2.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
* The Efergy e2 electricity monitor (http://efergy.com/it/products/electricity-monitors/e2-classic)
* provides a sensor that wirelessly sends information about the amount of electricity
* you are using to the display monitor. The monitor converts this into kilowatt-hours.
*
* This sketch use a JeeNode v5 (http://jeelabs.net/projects/hardware/wiki/JeeNode) equipped
* with 433/868 MHz RFM12B module (www.hoperf.com/upload/rf/RFM12B.pdf) configured in OOK mode
* to capture wireless data (on pin D3) and forward it through NRF24L01+ with MySensors library
*
* Created by Gennaro Tortone <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
// Enable debug prints to serial monitor
#define MY_DEBUG
//#define VERBOSE
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
// Enable and select radio type attached
#define MY_RADIO_NRF24
#define MY_RF24_CS_PIN 8
#define MY_RF24_CE_PIN 9
#define MY_RF24_PA_LEVEL RF24_PA_MAX
#include <SPI.h>
#include <MySensors.h>
#include <JeeLib.h>
#define DATA 3
#define CHILD_ID_POWER 9
unsigned long SLEEP_TIME = 2000; // Sleep time between reads (in milliseconds)
MyMessage msg(CHILD_ID_POWER, V_WATT);
enum { IDLE, START, ACQUIRE };
volatile byte state = IDLE;
volatile byte prevstate = IDLE;
byte payload[8];
byte nbytes = 0;
volatile bool lock = false;
bool decode_payload(byte *pl);
float current; // Ampere
byte voltage = 220; // Volt
float power; // Watt
uint16_t no_err, short_err, long_err, crc_err;
void setup()
{
Serial.begin(115200);
Serial.println("[Efergy e2]");
pinMode(DATA, INPUT);
attachInterrupt(digitalPinToInterrupt(DATA), efergy_e2_rx, CHANGE);
rf12_initialize(0, RF12_433MHZ);
rf12_control(0x8097); // disable FIFO
rf12_control(0xA586); // frequency to 433.535 MHz
rf12_control(0xC622); // data rate: 10142 bps
rf12_control(0xCC76); // max bw 86.2 kbps
rf12_control(0x94C4); // bandwidth changed to 67 kHz, LNA gain 0 dB
rf12_control(0x82DD); // RECEIVER_ON
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Efergy e2 power meter", "1.0");
// Register all sensors to gateway (they will be created as child devices)
present(CHILD_ID_POWER, S_POWER);
no_err = short_err = long_err = crc_err = 0;
}
void loop()
{
while(!lock) ;
#ifdef VERBOSE
Serial.println("-- S --");
for(int i=0; i<nbytes; i++) {
Serial.println(payload[i]);
}
Serial.println("-- E --");
#endif
if(decode_payload()) {
#ifdef VERBOSE
Serial.print("current = ");
Serial.print(current);
Serial.print("A - power = ");
Serial.print(power);
Serial.println(" W");
#endif
send(msg.set((int16_t)(power)));
}
#ifdef VERBOSE
Serial.print("OK = ");
Serial.print(no_err);
Serial.print(" - short pk = ");
Serial.print(short_err);
Serial.print(" - long pk = ");
Serial.print(long_err);
Serial.print(" - crc bad = ");
Serial.println(crc_err);
#endif
lock = false;
}
bool decode_payload(void) {
uint16_t adc_value;
if(nbytes < 8) {
short_err++;
return 0;
}
if(!crc_payload()) {
crc_err++;
return 0;
}
// here crc is ok
if(nbytes > 8) {
// track if long packet
long_err++;
}
adc_value = (payload[4] << 8) + payload[5];
current = ((float)(adc_value) / 32768) * (float)(pow(2, payload[6]));
power = (float) (current * voltage);
no_err++;
return 1;
}
bool crc_payload(void) {
uint8_t val = 0;
for(int i=0; i<=6; i++)
val += payload[i];
if(val == payload[7])
return 1;
else
return 0;
}
/*
* Efergy e2 power monitor http://efergy.com/it/products/electricity-monitors/e2-classic
* transmission protocol features:
*
* frequency: 433.535 MHz
* bandwith: 67 kHz
* data rate: 10142 bps
*
* preamble: ~1800 us LOW - ~500 us HIGH
*
* payload:
* - '0' => 140 us LOW - 60 us HIGH
* - '1' => 60 us LOW - 140 HIGH
*
* payload format:
*
* 8 bytes
* -------
* bytes #1: 0x09 fixed value
* bytes #2: 0XF0 fixed value
* bytes #3: 0x2F fixed value
* bytes #4: 0x40 fixed value
* bytes #5: current MSB
* bytes #6: current LSB
* bytes #7: exponent
* bytes #8: CRC
*
* current detected = ((MSB << 8) + LSB / 32768) * pow(2, exponent)
*
* example:
*
* 0x09 0xF0 0x2F 0x40 0x6B 0x85 0x01 0x59
*
* current = (0x6B85 / 32768) * (2^1) = 27525/32768 * 2 = 0.839 * 2 = 1.67 A
*
*/
void efergy_e2_rx(void) {
static uint32_t lasttime = 0;
static uint32_t duration = 0;
static byte pos = 0;
static byte samples = 0;
static uint16_t nbits = 0;
static byte value = 0;
uint32_t t = micros();
if(lock) return;
duration = t - lasttime;
if( (state == START) ) {
if( (duration >= 400) && (duration <= 700) ) {
prevstate = state; // START -> ACQUIRE
state = ACQUIRE;
pos = samples = nbits = value = 0;
} else {
prevstate = state; // START -> IDLE
state = IDLE;
}
} else if(state == ACQUIRE) {
if( (duration <= 200) && (duration >= 10) ) {
samples++;
if(samples == 2) {
if( duration <= 100 ) { // bit = 0
nbits++;
value = value << 1;
if(nbits % 8 == 0) {
payload[pos++] = value;
value = 0;
}
} else { // bit = 1
nbits++;
value = (value << 1) + 1;
if(nbits % 8 == 0) {
payload[pos++] = value;
value = 0;
}
}
samples = 0;
}
} else {
prevstate = state; // ACQUIRE -> IDLE
state = IDLE;
nbytes = pos;
lock = true;
}
} else if(state == IDLE) {
if(duration >= 1800) {
prevstate = state; // IDLE -> START
state = START;
}
}
lasttime = t;
}