#include "lvgl.h" #include "pins_config.h" #include "AXS15231B.h" #include "ui-util.h" #include "WiFi.h" #include "sntp.h" #include "time.h" #include #include #include #include "freertos/semphr.h" // Serial #define BAUD 115200 // Sensor pins #define RX2_PIN TOUCH_IICSCL #define TX2_PIN TOUCH_IICSDA // Sensor configuration #define COMMAND "FDFCFBFA0800120000006400000004030201" //Normal mode command, see documentation waveshare sensor #define PRESENCE_DISTANCE 200 // in cm #define DELAY_STATUS_CHECK 1000 // delay (in ms) between two checks of the presence #define SLEEP_DELAY 10000 // delay (in ms) until sleep mode #define POWER_DELAY 30000 // delay (in ms) until turning off the screen SemaphoreHandle_t xSemaphore = NULL; PowersSY6970 PMU; // Sensor variables uint16_t state = 1; // 0 = presence detected, 1 = no presence detected for the past SLEEP_DELAY ms, 2 = no presence detected for the past POWER_DELAY ms unsigned long lastMotionCheckTime = millis(); unsigned long lastMotionDetected = 0; // Time variables static uint32_t last_tick; struct tm timeinfo; uint32_t cycleInterval = 0; // Display variables static lv_disp_draw_buf_t draw_buf; static lv_color_t *buf; static lv_color_t *buf1; // REST API Home assistant request static String BASE_URL_HA = "http://192.168.1.2:8123/api/services"; static String HA_TOKEN = "abc"; void setup() { xSemaphore = xSemaphoreCreateBinary(); xSemaphoreGive(xSemaphore); initSerial(); initializeWifi(); initializeTime(); sendCommandAsHex(COMMAND); initializeUI(); } void loop() { delay(1); if (transfer_num <= 0 && lcd_PushColors_len <= 0) lv_timer_handler(); if (transfer_num <= 1 && lcd_PushColors_len > 0) { lcd_PushColors(0, 0, 0, 0, NULL); } static int flag_bl = 0; static unsigned long cnt = 0; printLocalTime(); readAndProcessSensorLines(); cnt++; if (cnt >= 100) { if (flag_bl == 0) { pinMode(TFT_BL, OUTPUT); digitalWrite(TFT_BL, HIGH); flag_bl = 1; lv_delay_ms(500); ui_begin(); } } } void initSerial() { // Start the primary serial communication (USB Monitor) Serial.begin(BAUD); unsigned long startAttemptTime = millis(); while (!Serial && millis() - startAttemptTime < 2000) { delay(100); } Serial.println("Serial Monitor Initialized."); pinMode(PIN_BAT_VOLT, ANALOG); // Screen pinMode(TOUCH_RES, OUTPUT); digitalWrite(TOUCH_RES, HIGH); delay(2); digitalWrite(TOUCH_RES, LOW); delay(10); digitalWrite(TOUCH_RES, HIGH); delay(2); // Start Serial2 for the HMMD Sensor Serial2.begin(BAUD, SERIAL_8N1, RX2_PIN, TX2_PIN); Serial.println("Serial2 Initialized on RX:" + String(RX2_PIN) + ", TX:" + String(TX2_PIN)); } void sendCommandAsHex(String hexString) { int hexStringLength = hexString.length(); if (hexStringLength % 2 != 0) { Serial.println("Error: Hex string must have an even number of characters."); return; } int byteCount = hexStringLength / 2; byte hexBytes[byteCount]; for (int i = 0; i < hexStringLength; i += 2) { String byteString = hexString.substring(i, i + 2); byte hexByte = (byte)strtoul(byteString.c_str(), NULL, 16); hexBytes[i / 2] = hexByte; } // Print confirmation of what's being sent Serial.print("Sending "); Serial.print(byteCount); Serial.print(" bytes: "); for(int i=0; i= WIFI_CONNECT_WAIT_MAX) { ESP.restart(); } } Serial.println(); Serial.println("Connection succesful!"); Serial.printf("SSID: %s\r\n", WiFi.SSID().c_str()); String IP = WiFi.localIP().toString(); Serial.printf("IP address: %s\r\n", IP.c_str()); } void initializeTime() { Serial.println("Initializing time..."); configTime(GMT_OFFSET_SEC, DAY_LIGHT_OFFSET_SEC, NTP_SERVER1, NTP_SERVER2); } void initializeUI() { Serial.println("Initializing UI...."); axs15231_init(); lv_init(); size_t buffer_size = sizeof(lv_color_t) * EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES; buf = (lv_color_t *)ps_malloc(buffer_size); if (buf == NULL) { while (1) { Serial.println("buf NULL"); delay(500); } } buf1 = (lv_color_t *)ps_malloc(buffer_size); if (buf1 == NULL) { while (1) { Serial.println("buf NULL"); delay(500); } } lv_disp_draw_buf_init(&draw_buf, buf, buf1, buffer_size); /*Initialize the display*/ static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); /*Change the following line to your display resolution*/ disp_drv.hor_res = EXAMPLE_LCD_H_RES; disp_drv.ver_res = EXAMPLE_LCD_V_RES; disp_drv.flush_cb = my_disp_flush; disp_drv.draw_buf = &draw_buf; disp_drv.sw_rotate = 1; // If you turn on software rotation, Do not update or replace LVGL disp_drv.rotated = LV_DISP_ROT_90; disp_drv.full_refresh = 1; // full_refresh must be 1 lv_disp_drv_register(&disp_drv); static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; lv_indev_drv_register(&indev_drv); Serial.println("UI initialized"); } void printLocalTime() { if (millis() - last_tick > 100) { struct tm timeInfo; if(!getLocalTime(&timeInfo)){ Serial.println("Failed to obtain time"); } else { lv_msg_send(MSG_NEW_HOUR, &timeInfo.tm_hour); lv_msg_send(MSG_NEW_MIN, &timeInfo.tm_min); lv_msg_send(MSG_NEW_SEC, &timeInfo.tm_sec); } last_tick = millis(); } } void readAndProcessSensorLines() { if (millis() - lastMotionCheckTime >= DELAY_STATUS_CHECK) { lastMotionCheckTime = millis(); // Check if data is available on Serial2 while (Serial2.available() > 0) { // Read a line of text until a newline character (\n) is received // The timeout helps prevent blocking forever if a line ending is missed String line = Serial2.readStringUntil('\n'); // Clean up the line: remove potential carriage return (\r) and leading/trailing whitespace line.trim(); // Check if the line contains the "Range" information if (line.startsWith("Range ")) { // Extract the substring after "Range " String distanceStr = line.substring(6); int distance = distanceStr.toInt(); bool currentStatus = distance <= PRESENCE_DISTANCE; if (currentStatus) { lastMotionDetected = millis(); } if (currentStatus && state != 0) { state = 0; Serial.println("Motion detected, turning screen on."); //rest_api_action(0); } else if (!currentStatus && state == 1 && (millis() - lastMotionDetected >= POWER_DELAY)) { state = 2; Serial.printf("No motion detected for %d seconds, turning screen off.\n", POWER_DELAY); //rest_api_action(2); } else if (!currentStatus && state == 0 && (millis() - lastMotionDetected >= SLEEP_DELAY)) { state = 1; Serial.printf("No motion detected for %d seconds, turning screen screensaver on.\n", SLEEP_DELAY); //rest_api_action(1); } } } } } // action: 0 => Screen on, => 1 Screen off, => 2 Power off void rest_api_action(int action) { WiFiClient client; HTTPClient http; int httpResponseCode; String url; if(WiFi.status() != WL_CONNECTED){ Serial.println("WiFi Disconnected. No request sent"); } switch (action) { case 0: // Screen on Serial.println("Sending Screen ON Request"); url = BASE_URL_HA + "/webostv/command"; http.begin(client, url); http.addHeader("Authorization", "Bearer " + HA_TOKEN); http.addHeader("Content-Type", "application/json"); httpResponseCode = http.POST("{\"entity_id\":\"media_player.lg_webos_smart_tv\",\"command\":\"com.webos.service.tvpower/power/turnOnScreen\"}"); break; case 1: // Screen off Serial.println("Sending Screen OFF Request"); url = BASE_URL_HA + "/webostv/command"; http.begin(client, url); http.addHeader("Authorization", "Bearer " + HA_TOKEN); http.addHeader("Content-Type", "application/json"); httpResponseCode = http.POST("{\"entity_id\":\"media_player.lg_webos_smart_tv\",\"command\":\"com.webos.service.tvpower/power/turnOffScreen\"}"); break; case 2: // Power off Serial.println("Sending Power Off Request"); url = BASE_URL_HA + "/webostv/command"; http.begin(client, url); http.addHeader("Authorization", "Bearer " + HA_TOKEN); http.addHeader("Content-Type", "application/json"); httpResponseCode = http.POST("{\"entity_id\":\"media_player.lg_webos_smart_tv\",\"command\":\"com.webos.service.tvpower/power/powerOffScreen\"}"); break; } Serial.print("HTTP Response code: "); Serial.println(httpResponseCode); http.end(); }