├── .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 | Buy Me A Coffee 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 | ![](resources/Animation.gif) 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 --------------------------------------------------------------------------------