91 u8g2_DrawStr(&u8g2, (128 - w) / 2,12, buf); |
91 u8g2_DrawStr(&u8g2, (128 - w) / 2,12, buf); |
92 } |
92 } |
93 |
93 |
94 |
94 |
95 |
95 |
|
96 void screen_splash() |
|
97 { |
|
98 screen_top("CO2 meter %s", app_desc->version); |
|
99 |
|
100 u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf); |
|
101 u8g2_uint_t w = u8g2_GetUTF8Width(&u8g2, "START"); |
|
102 u8g2_DrawUTF8(&u8g2, (128 - w) / 2,50, "START"); |
|
103 |
|
104 u8g2_SendBuffer(&u8g2); |
|
105 u8g2_SetPowerSave(&u8g2, 0); // wake up display |
|
106 } |
|
107 |
|
108 |
|
109 |
96 void screen_main() |
110 void screen_main() |
97 { |
111 { |
98 char buf[65]; |
112 char buf[65]; |
99 int i; |
113 int i; |
100 |
114 |
140 |
154 |
141 xSemaphoreGive(xSemaphoreUnits); |
155 xSemaphoreGive(xSemaphoreUnits); |
142 } |
156 } |
143 u8g2_SendBuffer(&u8g2); |
157 u8g2_SendBuffer(&u8g2); |
144 u8g2_SetPowerSave(&u8g2, 0); // wake up display |
158 u8g2_SetPowerSave(&u8g2, 0); // wake up display |
|
159 } |
|
160 |
|
161 |
|
162 |
|
163 void screen_unit_zero(int no, int sub) |
|
164 { |
|
165 screen_top("Unit %d zero mV", no + 1); |
|
166 menu_line( 0, 2, 25, "Current %d", units[no].pressure_zero); |
|
167 menu_line(sub == 0, 2, 37, "New value %d", units[no].pressure_voltage / (adc_state->Batt_voltage / 1000)); |
|
168 menu_line(sub == 1, 2, 49, "Return"); |
|
169 |
|
170 u8g2_SendBuffer(&u8g2); |
|
171 u8g2_SetPowerSave(&u8g2, 0); |
145 } |
172 } |
146 |
173 |
147 |
174 |
148 |
175 |
149 void screen_unit_setup(int no, int sub) |
176 void screen_unit_setup(int no, int sub) |
223 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); |
250 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); |
224 } |
251 } |
225 |
252 |
226 |
253 |
227 |
254 |
|
255 int rotate_to_sub(rotary_encoder_position_t pos, int min, int max, int cursub) |
|
256 { |
|
257 int sub = cursub; |
|
258 |
|
259 if (pos > 0) { |
|
260 if (sub < max) |
|
261 sub++; |
|
262 else |
|
263 sub = min; |
|
264 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); |
|
265 } else if (pos < 0) { |
|
266 if (sub > min) |
|
267 sub--; |
|
268 else |
|
269 sub = max; |
|
270 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); |
|
271 } |
|
272 return sub; |
|
273 } |
|
274 |
|
275 |
228 void app_main() |
276 void app_main() |
229 { |
277 { |
230 struct timeval now; |
278 struct timeval now; |
231 gettimeofday(&now, NULL); |
279 gettimeofday(&now, NULL); |
232 int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000; |
280 int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000; |
233 esp_err_t ret; |
281 esp_err_t ret; |
234 |
282 |
235 Main_Loop1 = ML1_INIT; |
283 Main_Loop1 = ML1_INIT; |
236 Main_Loop2 = -1; |
284 Main_Loop2 = -1; |
237 |
285 |
|
286 /* |
|
287 * Setup the OLED display. |
|
288 * See: https://github.com/nkolban/esp32-snippets/blob/master/hardware/displays/U8G2/ |
|
289 */ |
|
290 u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; |
|
291 u8g2_esp32_hal.sda = PIN_SDA; |
|
292 u8g2_esp32_hal.scl = PIN_SCL; |
|
293 u8g2_esp32_hal_init(u8g2_esp32_hal); |
|
294 |
|
295 u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure |
|
296 u8x8_SetI2CAddress(&u8g2.u8x8, 0x78); |
|
297 u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, |
|
298 |
|
299 app_desc = esp_ota_get_app_description(); |
|
300 |
238 switch (esp_sleep_get_wakeup_cause()) { |
301 switch (esp_sleep_get_wakeup_cause()) { |
239 case ESP_SLEEP_WAKEUP_EXT1: { |
302 case ESP_SLEEP_WAKEUP_EXT1: { |
240 ESP_LOGI(TAG, "Starting from deep sleep, Rotary switch pressed"); |
303 ESP_LOGI(TAG, "Starting from deep sleep, Rotary switch pressed"); |
241 New_Loop2 = ML2_INIT; |
304 New_Loop2 = ML2_INIT; |
|
305 screen_splash(); |
242 break; |
306 break; |
243 } |
307 } |
244 case ESP_SLEEP_WAKEUP_TIMER: { |
308 case ESP_SLEEP_WAKEUP_TIMER: { |
245 ESP_LOGI(TAG, "Starting from deep sleep, timer wakeup after %dms", sleep_time_ms); |
309 ESP_LOGI(TAG, "Starting from deep sleep, timer wakeup after %dms", sleep_time_ms); |
246 break; |
310 break; |
247 } |
311 } |
248 case ESP_SLEEP_WAKEUP_UNDEFINED: |
312 case ESP_SLEEP_WAKEUP_UNDEFINED: |
249 default: |
313 default: |
250 ESP_LOGI(TAG, "Starting from hard reset"); |
314 ESP_LOGI(TAG, "Starting from hard reset"); |
|
315 screen_splash(); |
251 } |
316 } |
252 |
317 |
253 const int wakeup_time_sec = 55; |
318 const int wakeup_time_sec = 55; |
254 ESP_LOGI(TAG, "Enabling timer wakeup, %ds", wakeup_time_sec); |
319 ESP_LOGI(TAG, "Enabling timer wakeup, %ds", wakeup_time_sec); |
255 esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000); |
320 esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000); |
260 |
325 |
261 // Isolate GPIO12 pin from external circuits. This is needed for modules |
326 // Isolate GPIO12 pin from external circuits. This is needed for modules |
262 // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) |
327 // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) |
263 // to minimize current consumption. |
328 // to minimize current consumption. |
264 // rtc_gpio_isolate(GPIO_NUM_12); |
329 // rtc_gpio_isolate(GPIO_NUM_12); |
265 |
|
266 app_desc = esp_ota_get_app_description(); |
|
267 |
330 |
268 /* |
331 /* |
269 * Initialize NVS |
332 * Initialize NVS |
270 */ |
333 */ |
271 ret = nvs_flash_init(); |
334 ret = nvs_flash_init(); |
272 if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { |
335 if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { |
273 ESP_ERROR_CHECK(nvs_flash_erase()); |
336 ESP_ERROR_CHECK(nvs_flash_erase()); |
274 ret = nvs_flash_init(); |
337 ret = nvs_flash_init(); |
275 } |
338 } |
276 ESP_ERROR_CHECK(ret); |
339 ESP_ERROR_CHECK(ret); |
277 |
|
278 /* |
|
279 * Setup the OLED display. |
|
280 * See: https://github.com/nkolban/esp32-snippets/blob/master/hardware/displays/U8G2/ |
|
281 */ |
|
282 u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; |
|
283 u8g2_esp32_hal.sda = PIN_SDA; |
|
284 u8g2_esp32_hal.scl = PIN_SCL; |
|
285 u8g2_esp32_hal_init(u8g2_esp32_hal); |
|
286 |
|
287 u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure |
|
288 u8x8_SetI2CAddress(&u8g2.u8x8, 0x78); |
|
289 u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, |
|
290 |
340 |
291 /* |
341 /* |
292 * Setup SPIFFS filesystem |
342 * Setup SPIFFS filesystem |
293 */ |
343 */ |
294 ESP_LOGI(TAG, "Initializing SPIFFS"); |
344 ESP_LOGI(TAG, "Initializing SPIFFS"); |
448 strncpy(units[i].temperature_rom_code, rom_code, 17); |
499 strncpy(units[i].temperature_rom_code, rom_code, 17); |
449 if (xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE) { |
500 if (xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE) { |
450 units[i].pressure_state = adc_state->Pressure[i].error; |
501 units[i].pressure_state = adc_state->Pressure[i].error; |
451 units[i].pressure_channel = adc_state->Pressure[i].channel; |
502 units[i].pressure_channel = adc_state->Pressure[i].channel; |
452 units[i].pressure_voltage = adc_state->Pressure[i].voltage; |
503 units[i].pressure_voltage = adc_state->Pressure[i].voltage; |
453 units[i].pressure_zero = 110; |
|
454 if (units[i].pressure_state || units[i].pressure_voltage < 80) |
504 if (units[i].pressure_state || units[i].pressure_voltage < 80) |
455 units[i].alarm |= ALARM_UNIT_PRESSURE; |
505 units[i].alarm |= ALARM_UNIT_PRESSURE; |
456 int P = (units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero) * 14; // in bar |
506 int P = (units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero) * 14; // in bar |
457 if (P < 0) |
507 if (P < 0) |
458 P = 0; |
508 P = 0; |
459 units[i].pressure = P; |
509 units[i].pressure = P; |
460 printf("%d volt: %d batt: %d scale: %d bar: %d\n", i, units[i].pressure_voltage, adc_state->Batt_voltage, |
510 printf("%d volt: %d batt: %d scale: %d mbar: %d\n", i, units[i].pressure_voltage, adc_state->Batt_voltage, |
461 units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P); |
511 units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P); |
462 // Moet die echt op 5 volt? |
512 // Moet die echt op 5 volt? |
463 // Verbruik 10 mA |
513 // Verbruik 10 mA |
464 // Setup tijd max 2 mS |
514 // Setup tijd max 2 mS |
465 xSemaphoreGive(xSemaphoreADC); |
515 xSemaphoreGive(xSemaphoreADC); |
568 ESP_LOGI(TAG, "Loop user: Setup Unit %d", Main_Loop2 - ML2_SETUP_UNIT1); |
618 ESP_LOGI(TAG, "Loop user: Setup Unit %d", Main_Loop2 - ML2_SETUP_UNIT1); |
569 sub = 0; |
619 sub = 0; |
570 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); |
620 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); |
571 break; |
621 break; |
572 |
622 |
|
623 case ML2_ZERO_UNIT1: |
|
624 case ML2_ZERO_UNIT2: |
|
625 case ML2_ZERO_UNIT3: |
|
626 ESP_LOGI(TAG, "Loop user: Zero Unit %d", Main_Loop2 - ML2_ZERO_UNIT1); |
|
627 sub = 0; |
|
628 screen_unit_zero(Main_Loop2 - ML2_ZERO_UNIT1, sub); |
|
629 break; |
|
630 |
573 case ML2_INACTIVE: |
631 case ML2_INACTIVE: |
574 ESP_LOGI(TAG, "Loop user: Inactive"); |
632 ESP_LOGI(TAG, "Loop user: Inactive"); |
575 u8g2_SetPowerSave(&u8g2, 1); // powersave display |
633 u8g2_SetPowerSave(&u8g2, 1); // powersave display |
576 New_Loop2 = ML2_DONE; |
634 New_Loop2 = ML2_DONE; |
577 break; |
635 break; |
612 case ML2_SET_NETWORK: rotate_to_menu(event.state.position, ML2_SET_MQTT, ML2_SET_WIFI); break; |
670 case ML2_SET_NETWORK: rotate_to_menu(event.state.position, ML2_SET_MQTT, ML2_SET_WIFI); break; |
613 case ML2_SET_MQTT: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_NETWORK); break; |
671 case ML2_SET_MQTT: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_NETWORK); break; |
614 case ML2_UPDATE: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_MQTT); break; |
672 case ML2_UPDATE: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_MQTT); break; |
615 case ML2_SETUP_UNIT1: |
673 case ML2_SETUP_UNIT1: |
616 case ML2_SETUP_UNIT2: |
674 case ML2_SETUP_UNIT2: |
617 case ML2_SETUP_UNIT3: if (event.state.position > 0) { |
675 case ML2_SETUP_UNIT3: sub = rotate_to_sub(event.state.position, 0, 3, sub); |
618 if (sub < 3) { |
676 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); |
619 sub++; |
677 break; |
620 } else { |
678 case ML2_ZERO_UNIT1: |
621 sub = 0; |
679 case ML2_ZERO_UNIT2: |
622 } |
680 case ML2_ZERO_UNIT3: sub = rotate_to_sub(event.state.position, 0, 1, sub); |
623 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); |
681 screen_unit_zero(Main_Loop2 - ML2_ZERO_UNIT1, sub); |
624 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); |
|
625 } else if (event.state.position < 0) { |
|
626 if (sub > 0) { |
|
627 sub--; |
|
628 } else { |
|
629 sub = 3; |
|
630 } |
|
631 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); |
|
632 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); |
|
633 } |
|
634 break; |
682 break; |
635 default: |
683 default: |
636 ESP_LOGI(TAG, "Event: position %d, direction %s", event.state.position, |
684 ESP_LOGI(TAG, "Event: position %d, direction %s", event.state.position, |
637 event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW":"CCW"):"NOT_SET"); |
685 event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW":"CCW"):"NOT_SET"); |
638 } |
686 } |
653 } else |
701 } else |
654 New_Loop2 = ML2_INACTIVE; |
702 New_Loop2 = ML2_INACTIVE; |
655 } |
703 } |
656 } |
704 } |
657 |
705 |
658 switch (Main_Loop2) { |
706 /* |
659 // Break if all done and inactive. |
707 * Handle pressed rotary button. |
660 case ML2_UNIT1: |
708 */ |
661 case ML2_UNIT2: |
709 if (PushDuration) { |
662 case ML2_UNIT3: |
710 int idx = 0; |
663 if (PushDuration) { |
711 switch (Main_Loop2) { |
664 New_Loop2 = ML2_SETUP_UNIT1 + (Main_Loop2 - ML2_UNIT1); |
712 case ML2_UNIT1: |
665 PushDuration = 0; |
713 case ML2_UNIT2: |
|
714 case ML2_UNIT3: |
|
715 New_Loop2 = ML2_SETUP_UNIT1 + (Main_Loop2 - ML2_UNIT1); |
|
716 break; |
|
717 |
|
718 case ML2_SETUP_UNIT1: |
|
719 case ML2_SETUP_UNIT2: |
|
720 case ML2_SETUP_UNIT3: |
|
721 idx = Main_Loop2 - ML2_SETUP_UNIT1; |
|
722 if (sub == 0) { |
|
723 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) { |
|
724 if (units[idx].mode) |
|
725 units[idx].mode = 0; |
|
726 else |
|
727 units[idx].mode = 1; |
|
728 write_units(); |
|
729 xSemaphoreGive(xSemaphoreUnits); |
|
730 } |
|
731 screen_unit_setup(idx, sub); |
|
732 if (Main_Loop1 == ML1_DONE) |
|
733 Main_Loop1 = ML1_INIT; |
666 } |
734 } |
667 break; |
735 if (sub == 1) |
668 |
736 New_Loop2 = ML2_ZERO_UNIT1 + idx; |
669 case ML2_SETUP_UNIT1: |
737 if (sub == 3) |
670 case ML2_SETUP_UNIT2: |
738 New_Loop2 = ML2_UNIT1 + idx; |
671 case ML2_SETUP_UNIT3: |
739 printf("unit setup sub %d new %d idx %d\n", sub, New_Loop2, idx); |
672 if (PushDuration) { |
740 break; |
673 if (sub == 0) { |
741 |
674 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) { |
742 case ML2_ZERO_UNIT1: |
675 if (units[Main_Loop2 - ML2_SETUP_UNIT1].mode) |
743 case ML2_ZERO_UNIT2: |
676 units[Main_Loop2 - ML2_SETUP_UNIT1].mode = 0; |
744 case ML2_ZERO_UNIT3: |
677 else |
745 idx = Main_Loop2 - ML2_ZERO_UNIT1; |
678 units[Main_Loop2 - ML2_SETUP_UNIT1].mode = 1; |
746 if (sub == 0) { |
679 write_units(); |
747 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE && |
680 xSemaphoreGive(xSemaphoreUnits); |
748 xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE && |
681 } |
749 adc_state->Pressure[idx].voltage > 165 && |
682 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); |
750 adc_state->Pressure[idx].voltage < 660) { |
|
751 units[idx].pressure_zero = adc_state->Pressure[idx].voltage / (adc_state->Batt_voltage / 1000); |
|
752 write_units(); |
|
753 xSemaphoreGive(xSemaphoreADC); |
|
754 xSemaphoreGive(xSemaphoreUnits); |
|
755 screen_unit_zero(idx, sub); |
683 if (Main_Loop1 == ML1_DONE) |
756 if (Main_Loop1 == ML1_DONE) |
684 Main_Loop1 = ML1_INIT; |
757 Main_Loop1 = ML1_INIT; |
685 } |
758 } |
686 if (sub == 3) |
|
687 New_Loop2 = ML2_UNIT1 + (Main_Loop2 - ML2_SETUP_UNIT1); |
|
688 printf("sub %d new %d\n", sub, New_Loop2); |
|
689 PushDuration = 0; |
|
690 } |
759 } |
691 break; |
760 if (sub == 1) { |
692 |
761 New_Loop2 = ML2_SETUP_UNIT1 + idx; |
693 default: |
762 sub = 1; |
694 break; |
763 } |
|
764 printf("unit zero sub %d new %d idx %d\n", sub, New_Loop2, idx); |
|
765 break; |
|
766 |
|
767 default: |
|
768 break; |
|
769 } |
|
770 PushDuration = 0; |
695 } |
771 } |
696 |
772 |
697 if (Main_Loop1 == ML1_DONE && Main_Loop2 == ML2_DONE) |
773 if (Main_Loop1 == ML1_DONE && Main_Loop2 == ML2_DONE) |
698 break; |
774 break; |
699 |
775 |