├── .gitignore
├── CMakeLists.txt
├── Makefile
├── README.md
├── components
└── iec1107
│ ├── CMakeLists.txt
│ ├── iec1107.c
│ └── include
│ ├── config.h
│ └── iec1107.h
├── main
├── CMakeLists.txt
├── component.mk
└── main.c
└── resources
└── Animation.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | # Eclipse
55 | .metadata/
56 | RemoteSystemsTempFiles/.project
57 | .settings/
58 | *.a
59 | *.o
60 | *.d
61 | .cproject
62 | .project
63 | sdkconfig
64 | sdkconfig.old
65 | **/build/
66 | **/esp_idf_components/
67 | #doxygen
68 | Doxyfile
69 | .project
70 | .cproject
71 |
72 | # Visual Studio Code
73 | .vscode/
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # For more information about build system see
2 | # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
3 | # The following five lines of boilerplate have to be in your project's
4 | # CMakeLists in this exact order for cmake to work correctly
5 | cmake_minimum_required(VERSION 3.5)
6 |
7 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
8 | get_filename_component(ProjectId ${CMAKE_CURRENT_LIST_DIR} NAME)
9 | string(REPLACE " " "_" ProjectId ${ProjectId})
10 | project(${ProjectId})
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a
3 | # project subdirectory.
4 | #
5 |
6 | PROJECT_NAME := sample_project
7 |
8 | include $(IDF_PATH)/make/project.mk
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # What is esp32-iec62056-component
4 |
5 | esp32-iec62056-component is a pure C esp-idf component for ESP32 that allows reading electricity meters with optical eye.
6 |
7 | ## Example
8 |
9 | The project **example** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
10 |
11 | ## List of events
12 | * IEC1107_PROTOCOL_ERROR
13 | * IEC1107_START_MESSAGE_NOT_SENDED
14 | * IEC1107_START_MESSAGE_SENDED
15 | * IEC1107_START_MESSAGE_NOT_RECIEVED
16 | * IEC1107_START_MESSAGE_RECEIVED
17 | * IEC1107_READOUT_MESSAGE_SENDED
18 | * IEC1107_READOUT_MESSAGE_NOT_RECEIVED
19 | * IEC1107_READOUT_MESSAGE_RECEIVED
20 | * IEC1107_FIELDS_UPDATED
21 |
22 | ## When you adding esp32-iec62056-component to your code
23 | ```
24 | #include "iec1107.h"
25 | ```
26 |
27 | Add this two line
28 | ```
29 | extern export_values_t* export_hdl;
30 | extern const int export_params_size;
31 | ```
32 |
33 | Event handler function
34 | ```
35 | static void iec1107_event_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
36 | {
37 | switch(event_id)
38 | {
39 | case IEC1107_PROTOCOL_ERROR:
40 | ESP_LOGI("Event Handler", "IEC1107_PROTOCOL_ERROR");
41 | break;
42 | case IEC1107_START_MESSAGE_NOT_RECIEVED:
43 | ESP_LOGI("Event Handler", "IEC1107_START_MESSAGE_NOT_RECIEVED");
44 | break;
45 | case IEC1107_START_MESSAGE_NOT_SENDED:
46 | ESP_LOGI("Event Handler", "IEC1107_START_MESSAGE_NOT_SENDED");
47 | break;
48 | case IEC1107_START_MESSAGE_SENDED:
49 | ESP_LOGI("Event Handler", "IEC1107_START_MESSAGE_SENDED");
50 | break;
51 | case IEC1107_START_MESSAGE_RECEIVED:
52 | ESP_LOGI("Event Handler", "SIEC1107_START_MESSAGE_RECEIVED");
53 | break;
54 | case IEC1107_READOUT_MESSAGE_SENDED:
55 | ESP_LOGI("Event Handler", "IEC1107_READOUT_MESSAGE_SENDED");
56 | break;
57 | case IEC1107_READOUT_MESSAGE_NOT_RECEIVED:
58 | ESP_LOGI("Event Handler", "IEC1107_READOUT_MESSAGE_NOT_RECEIVED");
59 | break;
60 | case IEC1107_READOUT_MESSAGE_RECEIVED:
61 | ESP_LOGI("Event Handler", "IEC1107_READOUT_MESSAGE_RECEIVED");
62 | break;
63 | case IEC1107_FIELDS_UPDATED:
64 | print_exported_fields();
65 | ESP_LOGI("Event Handler", "IEC1107_FIELDS_UPDATED");
66 | break;
67 |
68 | default:
69 | break;
70 | }
71 | }
72 | ```
73 |
74 |
75 | Our main
76 | ```
77 | void app_main()
78 | {
79 | iec1107_parser_handle_t iec1107 = iec1107_parser_init(LOOP, 1000);
80 |
81 | iec1107_parser_add_handler(iec1107, iec1107_event_handler, NULL);
82 |
83 | iec1107_start(iec1107);
84 | }
85 | ```
86 |
87 | ## Adding obis code
88 |
89 | You can edit `export_obis_code` [config.h](components/iec1107/include/config.h)
90 | Example :
91 | ```
92 | const char* export_obis_code[] =
93 | {
94 | "32.7.0",
95 | "1.8.0",
96 | "34.7.0",
97 | "96.77.2*1",
98 | };
99 | ```
100 |
101 | I will calculate the values using the order found above. You can access these values through this struct. `export_hdl` We have already defined it in [main.c](main/main.c).
102 |
103 | For examle above `export_obis_code`
104 |
105 | When the reading from the meter is finished. All values are placed in the export_hdl variable. If you want to access the value of 32.7.0.
106 | `export_hdl -> export_holder[0]` It holds this value.
107 |
108 | 
109 |
--------------------------------------------------------------------------------
/components/iec1107/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "iec1107.c"
2 | INCLUDE_DIRS "include")
3 |
4 |
--------------------------------------------------------------------------------
/components/iec1107/iec1107.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "iec1107.h"
8 | #include "config.h"
9 |
10 | #define IEC1107_PARSER_RUNTIME_BUFFER_SIZE (1024)
11 | #define IEC1107_PARSER_RING_BUFFER_SIZE (IEC1107_PARSER_RUNTIME_BUFFER_SIZE * 2)
12 | #define IEC1107_UART_NUM UART_NUM_1
13 | #define IEC1107_START_MESSAGE_BAUD (300)
14 | #define IEC1107_READOUT_MESSAGE_BAUD (9600)
15 |
16 | //Think twice before change this value
17 | #define IEC1107_EVENT_LOOP_QUEUE_SIZE (35)
18 |
19 | /*
20 | * @brief Define of NMEA Parser Event base
21 | *
22 | */
23 | ESP_EVENT_DEFINE_BASE(IEC1107_EVENT);
24 |
25 | static const char *IEC1107_TAG = "iec1107_parser";
26 |
27 | /* @brief Software Timer to reading meter */
28 | static TimerHandle_t iec1107_cycle_timer = NULL;
29 |
30 | /* @brief FreeRTOS event group to signal when we need to make a start & readout request */
31 | static EventGroupHandle_t s_iec1107_event_group;
32 |
33 | /* @brief indicate flags event management */
34 | static const int START_MESSAGE_SEND = BIT0;
35 | static const int START_MESSAGE_SENDED = BIT1;
36 | static const int READOUT_MESSAGE_SEND = BIT2;
37 | static const int READOUT_MESSAGE_SENDED = BIT3;
38 | static const int READOUT_MESSAGE_ENDED = BIT4;
39 |
40 | typedef struct {
41 | uint8_t* buffer; ///< Run time buffer
42 | uint16_t timeout; ///< Periodic Timer
43 | reading_mode_t read_mode;
44 | uart_port_t uart_port;
45 | esp_event_loop_handle_t event_loop_hdl;
46 | TaskHandle_t tsk_hdl;
47 | QueueHandle_t ev_queue;
48 | }iec1107_t;
49 |
50 | export_values_t* export_hdl = NULL;
51 |
52 | static export_values_t* export_val_init()
53 | {
54 | export_values_t* hdl = calloc(1, sizeof(export_values_t));
55 |
56 | if (!hdl)
57 | {
58 | goto err_hdl;
59 | }
60 |
61 | hdl -> export_holder = calloc(1, sizeof(char*) * export_params_size);
62 |
63 | if (!hdl -> export_holder)
64 | {
65 | goto err_export_holder;
66 | }
67 |
68 | for (int i = 0; i < export_params_size; ++i)
69 | {
70 | /*
71 | * Ex :
72 | * Obis Code 96.77.0*1, Found Val 14-07-25,16:23,14-07-25,16:23
73 | * 50 byte for Found Val
74 | */
75 | hdl -> export_holder[i] = calloc(1,sizeof(char) * 50);
76 | if (!hdl -> export_holder[i])
77 | {
78 | goto err_export_holder_item;
79 | }
80 | }
81 |
82 | return hdl;
83 |
84 | err_export_holder_item:
85 | for (int i = 0; i < export_params_size; ++i)
86 | {
87 | free(hdl -> export_holder[i]);
88 | }
89 | err_export_holder:
90 | free(hdl -> export_holder);
91 | err_hdl:
92 | free(hdl);
93 |
94 | return NULL;
95 | }
96 |
97 | static void export_val_deinit()
98 | {
99 | for (int i = 0; i < export_params_size; ++i)
100 | {
101 | free(export_hdl -> export_holder[i]);
102 | }
103 |
104 | free(export_hdl -> export_holder);
105 |
106 | free(export_hdl);
107 | }
108 |
109 | static void iec1107_timer_cb(TimerHandle_t xTimer)
110 | {
111 | ESP_LOGI(IEC1107_TAG, "Reading EM Starting Again..");
112 |
113 | /* Stop the timer */
114 | xTimerStop(xTimer, (TickType_t) 0);
115 |
116 | /*Attempt to send start message */
117 | xEventGroupSetBits(s_iec1107_event_group, START_MESSAGE_SEND);
118 | }
119 |
120 | static void iec1107_management_task(void* pvParameters)
121 | {
122 | iec1107_t* iec1107 = (iec1107_t*)pvParameters;
123 | EventBits_t bit;
124 | for(;;)
125 | {
126 | bit = xEventGroupGetBits(s_iec1107_event_group);
127 |
128 | // Send Start Message
129 | if (bit & START_MESSAGE_SEND)
130 | {
131 | uart_set_baudrate(iec1107 -> uart_port, 300);
132 |
133 | static const unsigned char hello_world[] = {0x2F, 0x3F, 0x21, 0x0D, 0x0A};
134 | static const size_t size = sizeof(hello_world) / sizeof(hello_world[0]);
135 |
136 | uart_write_bytes(iec1107 -> uart_port, (const char*)hello_world, size);
137 |
138 | esp_err_t r;
139 | do {
140 | r = uart_wait_tx_done(iec1107 -> uart_port, 1000 / portTICK_PERIOD_MS);
141 | if (r == ESP_ERR_TIMEOUT)
142 | {
143 | esp_event_post_to(iec1107 -> event_loop_hdl, IEC1107_EVENT, IEC1107_START_MESSAGE_NOT_SENDED, NULL, 0, 100 / portTICK_PERIOD_MS);
144 | }
145 | } while(r != ESP_OK);
146 |
147 | xEventGroupClearBits(s_iec1107_event_group, START_MESSAGE_SEND);
148 | xEventGroupSetBits(s_iec1107_event_group, START_MESSAGE_SENDED);
149 | esp_event_post_to(iec1107 -> event_loop_hdl, IEC1107_EVENT, IEC1107_START_MESSAGE_SENDED, NULL, 0, 100 / portTICK_PERIOD_MS);
150 | }
151 | //Send Readout Message
152 | else if (bit & READOUT_MESSAGE_SEND)
153 | {
154 | static const unsigned char readout_message[] = {0x06, 0x30, 0x35, 0x30, 0x0D, 0x0A};
155 | static const size_t size = sizeof(readout_message) / sizeof(readout_message[0]);
156 |
157 | uart_write_bytes(iec1107 -> uart_port, (const char*)readout_message, size);
158 |
159 | esp_err_t r;
160 | do {
161 | r = uart_wait_tx_done(iec1107 -> uart_port, 1000 / portTICK_PERIOD_MS);
162 | if (r == ESP_ERR_TIMEOUT)
163 | {
164 | esp_event_post_to(iec1107 -> event_loop_hdl, IEC1107_EVENT, IEC1107_READOUT_MESSAGE_NOT_RECEIVED, NULL, 0, 100 / portTICK_PERIOD_MS);
165 | }
166 | } while(r != ESP_OK);
167 |
168 | /*
169 | * To do : Determine Protocol B or C before switching the baud rate.
170 | */
171 | uart_set_baudrate(iec1107 -> uart_port, IEC1107_READOUT_MESSAGE_BAUD);
172 |
173 | xEventGroupClearBits(s_iec1107_event_group, READOUT_MESSAGE_SEND);
174 | xEventGroupSetBits(s_iec1107_event_group, READOUT_MESSAGE_SENDED);
175 |
176 | esp_event_post_to(iec1107 -> event_loop_hdl, IEC1107_EVENT, IEC1107_READOUT_MESSAGE_SENDED, NULL, 0, 100 / portTICK_PERIOD_MS);
177 |
178 | // if one shot mode activated, delete task itself
179 | if (iec1107 -> read_mode == SHOT)
180 | {
181 | vTaskDelete(NULL);
182 | }
183 | }
184 | //if reading mode is SHOT, code will not reach this statement
185 | else if (bit & READOUT_MESSAGE_ENDED)
186 | {
187 | ESP_LOGI(IEC1107_TAG, "Readout Message Ended");
188 | xEventGroupClearBits(s_iec1107_event_group, READOUT_MESSAGE_ENDED);
189 | }
190 |
191 | vTaskDelay(60); //Added for feeding wdt.
192 | }
193 |
194 | vTaskDelete(NULL);
195 | }
196 |
197 | //To Do : Calculate CRC
198 | static void export_line(esp_event_loop_handle_t hdl, const uint8_t* buffer)
199 | {
200 | //I think 20 is enough. think define a macro for this.
201 | char obis_code[20] = {0};
202 | char* p = NULL;
203 | p = strstr((const char*)buffer, "(");
204 | int idx = 0;
205 |
206 | //Remove magic number
207 | if (buffer[1] == '!')
208 | {
209 | esp_event_post_to(hdl, IEC1107_EVENT, IEC1107_READOUT_MESSAGE_RECEIVED, NULL, 0, 100 / portTICK_PERIOD_MS);
210 | esp_event_post_to(hdl, IEC1107_EVENT, IEC1107_FIELDS_UPDATED, NULL, 0, 100 / portTICK_PERIOD_MS);
211 | xEventGroupClearBits(s_iec1107_event_group, READOUT_MESSAGE_SENDED);
212 | xEventGroupSetBits(s_iec1107_event_group, READOUT_MESSAGE_ENDED);
213 | xTimerStart( iec1107_cycle_timer, (TickType_t)0 );
214 | return; // Don't remove return exp for this statement.
215 | }
216 |
217 | //To Do : Check STX and also maybe ETX
218 | //Skip the first [STX]
219 | buffer++;
220 |
221 | //Extract obis code
222 | /*
223 | * Ex :
224 | * buffer : 32.7.0(228.60*V)
225 | * p : (228.60*V)
226 | * Until buffer != (
227 | * obis code : 32.7.0
228 | * buffer : (228.60*V)
229 | */
230 | while (*buffer != *p)
231 | {
232 | obis_code[idx] = *buffer++;
233 | idx++;
234 | }
235 |
236 | obis_code[idx] = '\0';
237 |
238 | //buffer : 228.60*V)
239 | buffer++;
240 |
241 | idx = 0;
242 |
243 | //Extract value
244 | //I think 50 is enough. think define a macro for this.
245 | char buf[50] = {0};
246 | while (*p++ != ')')
247 | {
248 | buf[idx] = *buffer++;
249 | idx++;
250 | }
251 |
252 | //Remove ')' char
253 | buf[idx - 1] = '\0';
254 |
255 | for (int export_list_idx = 0; export_list_idx < export_params_size; ++export_list_idx)
256 | {
257 | if (strcmp(obis_code, export_obis_code[export_list_idx]) == 0)
258 | {
259 | strcpy(export_hdl -> export_holder[export_list_idx], buf);
260 | //ESP_LOGI(IEC1107_TAG, "Obis Code %s, Found Val %s", obis_code, buf);
261 | }
262 | }
263 | }
264 |
265 | static void handle_uart_pattern(iec1107_t* iec1107)
266 | {
267 | int pos = uart_pattern_pop_pos(iec1107 -> uart_port);
268 | if (pos != -1 )
269 | {
270 | int len = uart_read_bytes(iec1107 -> uart_port, iec1107 -> buffer, pos + 1, 100 / portTICK_PERIOD_MS);
271 | iec1107 -> buffer[len] = '\0';
272 |
273 | EventBits_t bit;
274 | bit = xEventGroupGetBits(s_iec1107_event_group);
275 |
276 | if (bit & START_MESSAGE_SENDED)
277 | {
278 | // Identification too short
279 | if (len < 6)
280 | {
281 | esp_event_post_to(iec1107 -> event_loop_hdl, IEC1107_EVENT, IEC1107_START_MESSAGE_NOT_RECIEVED, NULL, 0, 100 / portTICK_PERIOD_MS);
282 | xEventGroupClearBits(s_iec1107_event_group, START_MESSAGE_SENDED);
283 | return;
284 | }
285 |
286 | ESP_LOGI(IEC1107_TAG, "Identification %s", iec1107 -> buffer);
287 |
288 | xEventGroupClearBits(s_iec1107_event_group, START_MESSAGE_SENDED);
289 | xEventGroupSetBits(s_iec1107_event_group, READOUT_MESSAGE_SEND);
290 | }
291 | else if (bit & READOUT_MESSAGE_SENDED)
292 | {
293 | //ESP_LOGI(IEC1107_TAG, "Line %s", iec1107 -> buffer);
294 | export_line(iec1107 -> event_loop_hdl, iec1107 -> buffer);
295 | }
296 | }
297 | else
298 | {
299 | //uart_flush maybe ?
300 | }
301 | }
302 |
303 | static void iec1107_uart_event_task(void *pvParameters)
304 | {
305 | iec1107_t *iec1107 = (iec1107_t *)pvParameters;
306 | uart_event_t event;
307 |
308 | for(;;)
309 | {
310 | if(xQueueReceive(iec1107 -> ev_queue, (void * )&event, (portTickType)portMAX_DELAY))
311 | {
312 | switch(event.type)
313 | {
314 | case UART_DATA:
315 | break;
316 | case UART_FIFO_OVF:
317 | ESP_LOGI(IEC1107_TAG, "hw fifo overflow");
318 | uart_flush_input(iec1107 -> uart_port);
319 | xQueueReset(iec1107 -> ev_queue);
320 | break;
321 | case UART_BUFFER_FULL:
322 | ESP_LOGI(IEC1107_TAG, "ring buffer full");
323 | uart_flush_input(iec1107 -> uart_port);
324 | xQueueReset(iec1107 -> ev_queue);
325 | break;
326 | case UART_BREAK:
327 | ESP_LOGW(IEC1107_TAG, "uart rx break");
328 | break;
329 | case UART_PARITY_ERR:
330 | ESP_LOGE(IEC1107_TAG, "uart parity error");
331 | break;
332 | case UART_FRAME_ERR:
333 | ESP_LOGE(IEC1107_TAG, "uart frame error");
334 | break;
335 | case UART_PATTERN_DET:
336 | handle_uart_pattern(iec1107);
337 | break;
338 | default:
339 | ESP_LOGI(IEC1107_TAG, "uart event type: %d", event.type);
340 | break;
341 | }
342 | }
343 |
344 | esp_event_loop_run(iec1107 -> event_loop_hdl, pdMS_TO_TICKS(50));
345 | }
346 |
347 | vTaskDelete(NULL);
348 | }
349 |
350 | iec1107_parser_handle_t iec1107_parser_init(reading_mode_t mode, uint16_t timeout)
351 | {
352 | iec1107_t* iec1107 = calloc(1, sizeof(iec1107_t));
353 | if (!iec1107)
354 | {
355 | ESP_LOGE(IEC1107_TAG, "Calloc memory failed for iec1107 struct");
356 | goto err_struct;
357 | }
358 |
359 | iec1107 -> read_mode = mode;
360 | iec1107 -> timeout = timeout;
361 |
362 | iec1107_cycle_timer = xTimerCreate( NULL, pdMS_TO_TICKS(iec1107 -> timeout), pdFALSE, ( void * ) 0, iec1107_timer_cb);
363 |
364 |
365 | iec1107 -> buffer = calloc(1, IEC1107_PARSER_RUNTIME_BUFFER_SIZE);
366 | if (!iec1107 -> buffer)
367 | {
368 | ESP_LOGE(IEC1107_TAG, "Calloc memory failed for iec1107 buffer");
369 | goto err_buffer;
370 | }
371 |
372 | iec1107 -> uart_port = IEC1107_UART_NUM;
373 |
374 | uart_config_t port_config = {
375 | .baud_rate = IEC1107_START_MESSAGE_BAUD,
376 | .data_bits = UART_DATA_7_BITS,
377 | .parity = UART_PARITY_EVEN,
378 | .stop_bits = UART_STOP_BITS_1,
379 | .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
380 | };
381 |
382 | if (uart_param_config(iec1107 -> uart_port, &port_config))
383 | {
384 | ESP_LOGE(IEC1107_TAG, "IEC1107 Port Config Failed");
385 | goto err_port;
386 | }
387 |
388 | if (uart_set_pin(iec1107 -> uart_port, 4, 5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE))
389 | {
390 | ESP_LOGE(IEC1107_TAG, "IEC1107 Pin Config Failed");
391 | goto err_port;
392 | }
393 |
394 | if (uart_driver_install(iec1107 -> uart_port, IEC1107_PARSER_RING_BUFFER_SIZE, 0,
395 | IEC1107_EVENT_LOOP_QUEUE_SIZE, &iec1107 -> ev_queue, 0))
396 | {
397 | ESP_LOGE(IEC1107_TAG, "IEC1107 Port Driver Failed");
398 | goto err_driver;
399 | }
400 |
401 | uart_enable_pattern_det_baud_intr(iec1107 -> uart_port, '\r', 1, 9, 0, 0);
402 | uart_pattern_queue_reset(iec1107 -> uart_port, IEC1107_EVENT_LOOP_QUEUE_SIZE);
403 |
404 | uart_flush(iec1107 -> uart_port);
405 |
406 | esp_event_loop_args_t args = {
407 | .queue_size = IEC1107_EVENT_LOOP_QUEUE_SIZE,
408 | .task_name = NULL,
409 | };
410 |
411 | if (esp_event_loop_create(&args, &iec1107 -> event_loop_hdl))
412 | {
413 | ESP_LOGE(IEC1107_TAG, "IEC1107 Event Loop Failed");
414 | goto err_event_loop;
415 | }
416 |
417 | BaseType_t err = xTaskCreate(
418 | iec1107_uart_event_task,
419 | "iec1107_parser",
420 | 2048,
421 | iec1107,
422 | 12,
423 | &iec1107->tsk_hdl);
424 | if (err != pdTRUE)
425 | {
426 | ESP_LOGE(IEC1107_TAG, "create IEC1107 Uart Event task failed");
427 | goto err_task_create;
428 | }
429 |
430 | export_hdl = export_val_init();
431 | ESP_LOGI(IEC1107_TAG, "IEC1107 Create Ok");
432 |
433 | return iec1107;
434 |
435 | err_task_create:
436 | err_event_loop:
437 | err_driver:
438 | uart_driver_delete(iec1107 -> uart_port);
439 | err_port:
440 | err_buffer:
441 | free(iec1107 -> buffer);
442 | err_struct:
443 | free(iec1107);
444 |
445 | return NULL;
446 | }
447 |
448 | void iec1107_start(iec1107_parser_handle_t hdl)
449 | {
450 | iec1107_t *iec1107 = (iec1107_t*)hdl;
451 | s_iec1107_event_group = xEventGroupCreate();
452 |
453 | BaseType_t err = xTaskCreate(
454 | iec1107_management_task,
455 | NULL,
456 | 2048,
457 | iec1107,
458 | 12,
459 | NULL);
460 | if (err != pdTRUE)
461 | {
462 | ESP_LOGE(IEC1107_TAG, "create IEC1107 Management task failed");
463 | return;
464 | }
465 |
466 | xEventGroupSetBits(s_iec1107_event_group, START_MESSAGE_SEND);
467 | }
468 |
469 |
470 | esp_err_t iec1107_parser_deinit(iec1107_parser_handle_t hdl)
471 | {
472 | iec1107_t* iec1107 = (iec1107_t*)hdl;
473 | vTaskDelete(iec1107 -> tsk_hdl);
474 | esp_event_loop_delete(iec1107 -> event_loop_hdl);
475 | esp_err_t err = uart_driver_delete(iec1107 -> uart_port);
476 | free(iec1107 -> buffer);
477 | free(iec1107);
478 |
479 | export_val_deinit();
480 |
481 | return err;
482 | }
483 |
484 | esp_err_t iec1107_parser_add_handler(iec1107_parser_handle_t hdl, esp_event_handler_t event_handler, void* handler_arg)
485 | {
486 | iec1107_t* iec1107 = (iec1107_t*)hdl;
487 |
488 | return esp_event_handler_register_with(iec1107 -> event_loop_hdl, IEC1107_EVENT,
489 | ESP_EVENT_ANY_ID, event_handler, handler_arg);
490 | }
491 |
492 | esp_err_t iec1107_parser_remove_handler(iec1107_parser_handle_t hdl, esp_event_handler_t event_handler)
493 | {
494 | iec1107_t* iec1107 = (iec1107_t*)hdl;
495 |
496 | return esp_event_handler_unregister_with(iec1107 -> event_loop_hdl, IEC1107_EVENT, ESP_EVENT_ANY_ID, event_handler);
497 | }
498 |
--------------------------------------------------------------------------------
/components/iec1107/include/config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | /*
4 | * @brief You can add your obis codes that you want to export.
5 | * If the obis code you added is not taken from the electric
6 | * meter, its value will not be parsed.
7 | *
8 | */
9 | const char* export_obis_code[] =
10 | {
11 | "32.7.0",
12 | "1.8.0",
13 | "34.7.0",
14 | "96.77.2*1",
15 | };
16 |
17 | // Don't change anything about below line!.
18 | const int export_params_size = sizeof(export_obis_code) / sizeof(export_obis_code[0]);
19 |
--------------------------------------------------------------------------------
/components/iec1107/include/iec1107.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifdef __cplusplus
4 | extern "C" {
5 | #endif
6 |
7 | #include "esp_types.h"
8 | #include "esp_event.h"
9 | #include "esp_err.h"
10 | #include "driver/uart.h"
11 |
12 |
13 | /*
14 | * @brief Declare of IEC1107 Event base
15 | *
16 | */
17 | ESP_EVENT_DECLARE_BASE(IEC1107_EVENT);
18 |
19 | /*
20 | * @brief IEC1107 Reading Modes
21 | *
22 | */
23 | typedef enum {
24 | SHOT,
25 | LOOP,
26 | } reading_mode_t;
27 |
28 | /*
29 | * @brief IEC1107 Parser Handle
30 | *
31 | */
32 | typedef void *iec1107_parser_handle_t;
33 |
34 | /*
35 | * @brief IEC1107 Exported Values
36 | *
37 | */
38 | typedef struct {
39 | char** export_holder;
40 | }export_values_t;
41 |
42 |
43 | /*
44 | * @brief IEC1107 Parser Event ID
45 | *
46 | */
47 | typedef enum {
48 | IEC1107_PROTOCOL_ERROR,
49 |
50 | IEC1107_START_MESSAGE_NOT_SENDED,
51 | IEC1107_START_MESSAGE_SENDED,
52 | IEC1107_START_MESSAGE_NOT_RECIEVED,
53 | IEC1107_START_MESSAGE_RECEIVED,
54 |
55 | IEC1107_READOUT_MESSAGE_SENDED,
56 | IEC1107_READOUT_MESSAGE_NOT_RECEIVED,
57 | IEC1107_READOUT_MESSAGE_RECEIVED,
58 |
59 | IEC1107_FIELDS_UPDATED,
60 | } iec1107_event_id_t;
61 |
62 | /*
63 | * @brief Init IEC1107 Parser
64 | *
65 | * @param mode reading mode periodic or one shot
66 | * @param timeout cycle for periodic reading
67 | * @return iec1107_parser_handle_t handle of iec1107
68 | */
69 | iec1107_parser_handle_t iec1107_parser_init(reading_mode_t mode, uint16_t timeout);
70 |
71 | /*
72 | * @brief Start reading
73 | *
74 | * @param hdl handle of IEC1107 Parser
75 | */
76 | void iec1107_start(iec1107_parser_handle_t hdl);
77 |
78 | /*
79 | * @brief Deinit IEC1107 Parser
80 | *
81 | * @param hdl handle of IEC1107 Parser
82 | * @return esp_err_t
83 | */
84 | esp_err_t iec1107_parser_deinit(iec1107_parser_handle_t hdl);
85 |
86 | /*
87 | * @brief Add user defined handler for IEC1107 Parser
88 | *
89 | * @param hdl handle of IEC1107 Parser
90 | * @param event_handler user defined event handler
91 | * @param handler_arg handler specific arguments
92 | * @return esp_err_t
93 | */
94 | esp_err_t iec1107_parser_add_handler(iec1107_parser_handle_t hdl, esp_event_handler_t event_handler, void *handler_arg);
95 |
96 | /*
97 | * @brief Remove user defined handler for IEC1107 Parser
98 | *
99 | * @param hdl handle of IEC1107 Parser
100 | * @param event-handler user defined event handler
101 | */
102 | esp_err_t iec1107_parser_remove_handler(iec1107_parser_handle_t hdl, esp_event_handler_t event_handler);
103 |
104 | #ifdef __cplusplus
105 | }
106 | #endif
107 |
--------------------------------------------------------------------------------
/main/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "main.c"
2 | INCLUDE_DIRS ".")
3 |
--------------------------------------------------------------------------------
/main/component.mk:
--------------------------------------------------------------------------------
1 | #
2 | # "main" pseudo-component makefile.
3 | #
4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
5 |
--------------------------------------------------------------------------------
/main/main.c:
--------------------------------------------------------------------------------
1 | #include "iec1107.h"
2 | #include "esp_log.h"
3 |
4 | extern export_values_t* export_hdl;
5 | extern const int export_params_size;
6 |
7 | static void print_exported_fields()
8 | {
9 | for (int i = 0; i < export_params_size; ++i)
10 | {
11 | ESP_LOGI("Field Tag", "Exported Val %s", export_hdl -> export_holder[i]);
12 | }
13 | }
14 |
15 | static void iec1107_event_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
16 | {
17 | switch(event_id)
18 | {
19 | case IEC1107_PROTOCOL_ERROR:
20 | ESP_LOGI("Event Handler", "IEC1107_PROTOCOL_ERROR");
21 | break;
22 | case IEC1107_START_MESSAGE_NOT_RECIEVED:
23 | ESP_LOGI("Event Handler", "IEC1107_START_MESSAGE_NOT_RECIEVED");
24 | break;
25 | case IEC1107_START_MESSAGE_NOT_SENDED:
26 | ESP_LOGI("Event Handler", "IEC1107_START_MESSAGE_NOT_SENDED");
27 | break;
28 | case IEC1107_START_MESSAGE_SENDED:
29 | ESP_LOGI("Event Handler", "IEC1107_START_MESSAGE_SENDED");
30 | break;
31 | case IEC1107_START_MESSAGE_RECEIVED:
32 | ESP_LOGI("Event Handler", "SIEC1107_START_MESSAGE_RECEIVED");
33 | break;
34 | case IEC1107_READOUT_MESSAGE_SENDED:
35 | ESP_LOGI("Event Handler", "IEC1107_READOUT_MESSAGE_SENDED");
36 | break;
37 | case IEC1107_READOUT_MESSAGE_NOT_RECEIVED:
38 | ESP_LOGI("Event Handler", "IEC1107_READOUT_MESSAGE_NOT_RECEIVED");
39 | break;
40 | case IEC1107_READOUT_MESSAGE_RECEIVED:
41 | ESP_LOGI("Event Handler", "IEC1107_READOUT_MESSAGE_RECEIVED");
42 | break;
43 | case IEC1107_FIELDS_UPDATED:
44 | print_exported_fields();
45 | ESP_LOGI("Event Handler", "IEC1107_FIELDS_UPDATED");
46 | break;
47 |
48 | default:
49 | break;
50 | }
51 | }
52 |
53 | void app_main()
54 | {
55 | iec1107_parser_handle_t iec1107 = iec1107_parser_init(LOOP, 10000);
56 |
57 | iec1107_parser_add_handler(iec1107, iec1107_event_handler, NULL);
58 |
59 | iec1107_start(iec1107);
60 | }
61 |
--------------------------------------------------------------------------------
/resources/Animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/embedded4ever/esp32-iec62056-component/21c4ac683ca49e66d4bb03e5eafa7c7ae8d80c56/resources/Animation.gif
--------------------------------------------------------------------------------