5
5
6
6
and pushes these telegrams to websocket clients connected on '/raw'.
7
7
8
- There is also a websocket '/current' pushing the current wattage to connected clients.
8
+ There is also a websocket '/current' pushing the current usage stats to connected clients.
9
+
10
+ Finally there is a webserver at port 80 with an index page that connects to websocket '/current' and shows energy use info.
9
11
10
12
How to connect to a p1 port see: https://github.com/matthijskooijman/arduino-dsmr#connecting-the-p1-port
11
13
*/
30
32
#define I2C_SDA_PIN (5 )
31
33
#define I2C_SCL_PIN (4 )
32
34
35
+ /* settings for ntp time sync */
33
36
const char * NTP_POOL = " pool.ntp.org" ;
34
37
const char * TIMEZONE = " CET-1CEST,M3.5.0/2,M10.5.0/3" ; /* Central European Time - see http://www.remotemonitoringsystems.ca/time-zone-abbreviations.php */
35
38
@@ -41,19 +44,16 @@ const IPAddress SUBNET(255, 255, 255, 0); /* Usually 255,255,255,
41
44
const IPAddress PRIMARY_DNS (192 , 168 , 0 , 30 ); /* Check in your router */
42
45
const IPAddress SECONDARY_DNS (192 , 168 , 0 , 50 ); /* Check in your router */
43
46
44
- AsyncWebServer server (80 );
45
- AsyncWebSocket ws_raw (" /raw" );
46
- AsyncWebSocket ws_current (" /current" );
47
- HardwareSerial smartMeter (UART_NR);
48
- SSD1306 oled (OLED_ADDRESS, I2C_SDA_PIN, I2C_SCL_PIN);
49
- bool oledFound{false };
50
- uint8_t currentDay;
47
+ const char * WS_RAW_URL{" /raw" };
48
+ const char * WS_CURRENT_URL{" /current" };
51
49
52
- struct {
53
- int t1Start{0 };
54
- int t2Start{0 };
55
- int gasStart{0 };
56
- } today;
50
+ AsyncWebServer server (80 );
51
+ AsyncWebSocket ws_raw (WS_RAW_URL);
52
+ AsyncWebSocket ws_current (WS_CURRENT_URL);
53
+ HardwareSerial smartMeter (UART_NR);
54
+ SSD1306 oled (OLED_ADDRESS, I2C_SDA_PIN, I2C_SCL_PIN);
55
+ bool oledFound{false };
56
+ uint8_t currentMonthDay;
57
57
58
58
void setup () {
59
59
Serial.begin (115200 );
@@ -99,7 +99,7 @@ void setup() {
99
99
100
100
while (!getLocalTime (&timeinfo, 0 ))
101
101
delay (10 );
102
- currentDay = timeinfo.tm_mday ;
102
+ currentMonthDay = timeinfo.tm_mday ;
103
103
104
104
/* websocket setup */
105
105
ws_raw.onEvent (onEvent);
@@ -127,89 +127,28 @@ void setup() {
127
127
Serial.printf (" Listening on HardwareSerial(%i) with RXD_PIN=%i\n " , UART_NR, RXD_PIN);
128
128
}
129
129
130
- bool coldBoot{true };
131
- char currentUseString[200 ];
132
-
133
130
void loop () {
134
131
static String telegram{" " };
135
132
136
133
ws_raw.cleanupClients ();
137
134
ws_current.cleanupClients ();
138
135
139
136
while (smartMeter.available ()) {
140
-
141
137
const char incomingChar = smartMeter.read ();
142
-
143
- if (incomingChar != ' !' )
144
- telegram.concat (incomingChar);
145
- else {
146
- telegram.concat (incomingChar);
147
-
148
- /* checksum reached, wait for and read 6 more bytes then the telegram is received completely - see DSMR 5.0.2 ¶ 6.2 */
149
- while (smartMeter.available () < 6 ) delay (1 );
150
-
151
- while (smartMeter.available ()) telegram.concat ((char )smartMeter.read ());
152
-
153
- ws_raw.textAll (telegram);
154
-
155
- currentUseData data;
156
- const ParseResult<void > res = P1Parser::parse (&data, telegram.c_str (), telegram.length ());
157
-
158
- if (res.err )
159
- ESP_LOGE (TAG, " %s" , res.fullError (telegram.c_str (), telegram.c_str () + telegram.length ()));
160
- else
161
- {
162
- if (coldBoot) {
163
- today.t1Start = data.energy_delivered_tariff1 .int_val ();
164
- today.t2Start = data.energy_delivered_tariff2 .int_val ();
165
- today.gasStart = data.gas_delivered .int_val ();
166
- coldBoot = false ;
167
- };
168
-
169
- snprintf (currentUseString, sizeof (currentUseString), " %i\n %i\n %i\n %i\n %i\n %i\n %i\n %s" ,
170
- data.power_delivered .int_val (),
171
- data.energy_delivered_tariff1 .int_val (),
172
- data.energy_delivered_tariff2 .int_val (),
173
- data.gas_delivered .int_val (),
174
- data.energy_delivered_tariff1 .int_val () - today.t1Start ,
175
- data.energy_delivered_tariff2 .int_val () - today.t2Start ,
176
- data.gas_delivered .int_val () - today.gasStart ,
177
- (data.electricity_tariff .equals (" 0001" )) ? " laag" : " hoog"
178
- );
179
-
180
- ws_current.textAll (currentUseString);
181
-
182
- if (oledFound) {
183
- oled.clear ();
184
- oled.setFont (ArialMT_Plain_16);
185
- oled.drawString (oled.width () >> 1 , 0 , WiFi.localIP ().toString ());
186
- oled.setFont (ArialMT_Plain_24);
187
- oled.drawString (oled.width () >> 1 , 18 , String (data.power_delivered .int_val ()) + " W" );
188
- oled.display ();
189
- }
190
-
191
- /* check if we changed day and update starter values if so */
192
- struct tm timeinfo = {0 };
193
- getLocalTime (&timeinfo);
194
- if (currentDay != timeinfo.tm_mday ) {
195
- today.t1Start = data.energy_delivered_tariff1 .int_val ();
196
- today.t2Start = data.energy_delivered_tariff2 .int_val ();
197
- today.gasStart = data.gas_delivered .int_val ();
198
- currentDay = timeinfo.tm_mday ;
199
- }
200
- }
201
- telegram = " " ;
202
- }
138
+ telegram.concat (incomingChar);
139
+ if (' !' == incomingChar) parseAndSend (telegram);
203
140
}
204
141
delay (1 );
205
142
}
206
143
144
+ char currentUseString[200 ];
145
+
207
146
void onEvent (AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
208
147
switch (type) {
209
148
210
149
case WS_EVT_CONNECT :
211
150
ESP_LOGI (TAG, " [%s][%u] connect" , server->url (), client->id ());
212
- if (0 == strcmp (" /current " , server->url ()))
151
+ if (0 == strcmp (WS_CURRENT_URL , server->url ()))
213
152
client->text (currentUseString);
214
153
break ;
215
154
@@ -236,3 +175,66 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
236
175
default : ESP_LOGE (TAG, " unhandled ws event type" );
237
176
}
238
177
}
178
+
179
+ void parseAndSend (String& telegram) {
180
+ /* checksum reached, wait for and read 6 more bytes then the telegram is received completely - see DSMR 5.0.2 ¶ 6.2 */
181
+ while (smartMeter.available () < 6 ) delay (1 );
182
+
183
+ while (smartMeter.available ()) telegram.concat ((char )smartMeter.read ());
184
+
185
+ ws_raw.textAll (telegram);
186
+
187
+ currentUseData data;
188
+ const ParseResult<void > res = P1Parser::parse (&data, telegram.c_str (), telegram.length ());
189
+
190
+ if (res.err ) {
191
+ ESP_LOGE (TAG, " %s" , res.fullError (telegram.c_str (), telegram.c_str () + telegram.length ()));
192
+ telegram = " " ;
193
+ return ;
194
+ }
195
+ telegram = " " ;
196
+
197
+ static struct {
198
+ uint32_t t1Start{0 };
199
+ uint32_t t2Start{0 };
200
+ uint32_t gasStart{0 };
201
+ } today;
202
+
203
+ if (!today.t1Start ) {
204
+ today.t1Start = data.energy_delivered_tariff1 .int_val ();
205
+ today.t2Start = data.energy_delivered_tariff2 .int_val ();
206
+ today.gasStart = data.gas_delivered .int_val ();
207
+ };
208
+
209
+ snprintf (currentUseString, sizeof (currentUseString), " %i\n %i\n %i\n %i\n %i\n %i\n %i\n %s" ,
210
+ data.power_delivered .int_val (),
211
+ data.energy_delivered_tariff1 .int_val (),
212
+ data.energy_delivered_tariff2 .int_val (),
213
+ data.gas_delivered .int_val (),
214
+ data.energy_delivered_tariff1 .int_val () - today.t1Start ,
215
+ data.energy_delivered_tariff2 .int_val () - today.t2Start ,
216
+ data.gas_delivered .int_val () - today.gasStart ,
217
+ (data.electricity_tariff .equals (" 0001" )) ? " laag" : " hoog"
218
+ );
219
+
220
+ ws_current.textAll (currentUseString);
221
+
222
+ if (oledFound) {
223
+ oled.clear ();
224
+ oled.setFont (ArialMT_Plain_16);
225
+ oled.drawString (oled.width () >> 1 , 0 , WiFi.localIP ().toString ());
226
+ oled.setFont (ArialMT_Plain_24);
227
+ oled.drawString (oled.width () >> 1 , 18 , String (data.power_delivered .int_val ()) + " W" );
228
+ oled.display ();
229
+ }
230
+
231
+ /* check if we changed day and update starter values if so */
232
+ struct tm timeinfo = {0 };
233
+ getLocalTime (&timeinfo);
234
+ if (currentMonthDay != timeinfo.tm_mday ) {
235
+ today.t1Start = data.energy_delivered_tariff1 .int_val ();
236
+ today.t2Start = data.energy_delivered_tariff2 .int_val ();
237
+ today.gasStart = data.gas_delivered .int_val ();
238
+ currentMonthDay = timeinfo.tm_mday ;
239
+ }
240
+ }
0 commit comments