Apply modifications to mass-produced boards
- 3 channel power sensor ina3221 - io expander pca9557 - Some gpio moves - ... Signed-off-by: YoungSoo Shin <shinys000114@gmail.com>
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
/.idea
|
/.idea
|
||||||
sdkconfig.old
|
sdkconfig.old
|
||||||
/managed_components
|
/managed_components
|
||||||
|
sdkconfig
|
||||||
|
dependencies.lock
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
dependencies:
|
|
||||||
espressif/cmake_utilities:
|
|
||||||
component_hash: 05165f30922b422b4b90c08845e6d449329b97370fbd06309803d8cb539d79e3
|
|
||||||
dependencies:
|
|
||||||
- name: idf
|
|
||||||
require: private
|
|
||||||
version: '>=4.1'
|
|
||||||
source:
|
|
||||||
registry_url: https://components.espressif.com
|
|
||||||
type: service
|
|
||||||
version: 1.1.1
|
|
||||||
espressif/led_indicator:
|
|
||||||
component_hash: 5b2531835a989825c0dc94465e3481086473e086dca109b99bea5605d8e70396
|
|
||||||
dependencies:
|
|
||||||
- name: espressif/cmake_utilities
|
|
||||||
registry_url: https://components.espressif.com
|
|
||||||
require: private
|
|
||||||
version: '*'
|
|
||||||
- name: idf
|
|
||||||
require: private
|
|
||||||
version: '>=4.0'
|
|
||||||
- name: espressif/led_strip
|
|
||||||
registry_url: https://components.espressif.com
|
|
||||||
require: public
|
|
||||||
version: 2.5.5
|
|
||||||
source:
|
|
||||||
registry_url: https://components.espressif.com/
|
|
||||||
type: service
|
|
||||||
version: 1.1.1
|
|
||||||
espressif/led_strip:
|
|
||||||
component_hash: 28c6509a727ef74925b372ed404772aeedf11cce10b78c3f69b3c66799095e2d
|
|
||||||
dependencies:
|
|
||||||
- name: idf
|
|
||||||
require: private
|
|
||||||
version: '>=4.4'
|
|
||||||
source:
|
|
||||||
registry_url: https://components.espressif.com
|
|
||||||
type: service
|
|
||||||
version: 2.5.5
|
|
||||||
idf:
|
|
||||||
source:
|
|
||||||
type: idf
|
|
||||||
version: 5.4.0
|
|
||||||
joltwallet/littlefs:
|
|
||||||
component_hash: 8e12955f47e27e6070b76715a96d6c75fc2b44f069e8c33679332d9bdd3120c4
|
|
||||||
dependencies:
|
|
||||||
- name: idf
|
|
||||||
require: private
|
|
||||||
version: '>=5.0'
|
|
||||||
source:
|
|
||||||
registry_url: https://components.espressif.com/
|
|
||||||
type: service
|
|
||||||
version: 1.20.1
|
|
||||||
direct_dependencies:
|
|
||||||
- espressif/led_indicator
|
|
||||||
- joltwallet/littlefs
|
|
||||||
manifest_hash: 445ef18c991ae952f2f16ffe06a905b6d1414a42286212d7b2459fa32945a09c
|
|
||||||
target: esp32c3
|
|
||||||
version: 2.0.0
|
|
||||||
@@ -10,7 +10,7 @@ endif()
|
|||||||
|
|
||||||
# Register the component. Now, CMake knows how GZ_OUTPUT_FILE is generated
|
# Register the component. Now, CMake knows how GZ_OUTPUT_FILE is generated
|
||||||
# and can correctly handle the dependency for embedding.
|
# and can correctly handle the dependency for embedding.
|
||||||
idf_component_register(SRC_DIRS "app" "nconfig" "wifi" "indicator" "system" "service" "ina226"
|
idf_component_register(SRC_DIRS "app" "nconfig" "wifi" "indicator" "system" "service"
|
||||||
INCLUDE_DIRS "include"
|
INCLUDE_DIRS "include"
|
||||||
EMBED_FILES ${GZ_OUTPUT_FILE}
|
EMBED_FILES ${GZ_OUTPUT_FILE}
|
||||||
)
|
)
|
||||||
|
|||||||
83
main/Kconfig
83
main/Kconfig
@@ -2,27 +2,34 @@ menu "ODROID-MONITOR"
|
|||||||
menu "GPIO"
|
menu "GPIO"
|
||||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||||
|
|
||||||
config GPIO_INA226_SCL
|
config I2C_GPIO_SCL
|
||||||
int "INA226 SCL GPIO Num"
|
int "INA226 SCL GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
default 0
|
|
||||||
help
|
|
||||||
GPIO number for I2C Master data line.
|
|
||||||
|
|
||||||
config GPIO_INA226_SDA
|
|
||||||
int "INA226 SDA GPIO Num"
|
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
|
||||||
default 1
|
default 1
|
||||||
help
|
help
|
||||||
GPIO number for I2C Master data line.
|
GPIO number for I2C Master data line.
|
||||||
|
|
||||||
config GPIO_INA226_INT
|
config I2C_GPIO_SDA
|
||||||
int "INA226 ALERT GPIO Num"
|
int "INA226 SDA GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
default 10
|
default 0
|
||||||
help
|
help
|
||||||
GPIO number for I2C Master data line.
|
GPIO number for I2C Master data line.
|
||||||
|
|
||||||
|
config GPIO_INA3221_INT_CRITICAL
|
||||||
|
int "INA226 ALERT GPIO Num"
|
||||||
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
|
default 9
|
||||||
|
help
|
||||||
|
GPIO number for critical int pin.
|
||||||
|
|
||||||
|
config GPIO_INA3221_INT_WARNING
|
||||||
|
int "INA226 WARNING GPIO Num"
|
||||||
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
GPIO number for critical int pin.
|
||||||
|
|
||||||
config GPIO_UART_TX
|
config GPIO_UART_TX
|
||||||
int "UART TX GPIO Num"
|
int "UART TX GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
@@ -40,43 +47,57 @@ menu "ODROID-MONITOR"
|
|||||||
config GPIO_LED_STATUS
|
config GPIO_LED_STATUS
|
||||||
int "Status LED GPIO Num"
|
int "Status LED GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
default 8
|
default 2
|
||||||
help
|
help
|
||||||
GPIO number for LED.
|
GPIO number for LED.
|
||||||
|
|
||||||
config GPIO_LED_WIFI
|
config GPIO_LED_WIFI
|
||||||
int "Wi-Fi LED GPIO Num"
|
int "Wi-Fi LED GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
default 9
|
default 3
|
||||||
help
|
help
|
||||||
GPIO number for LED.
|
GPIO number for LED.
|
||||||
|
|
||||||
config GPIO_SW_12V
|
config EXPANDER_GPIO_SW_12V
|
||||||
int "12v Load Switch GPIO Num"
|
int "12v Load Switch GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
default 4
|
|
||||||
help
|
|
||||||
GPIO number for Load switch.
|
|
||||||
|
|
||||||
config GPIO_SW_5V
|
|
||||||
int "5v Load Switch GPIO Num"
|
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
|
||||||
default 5
|
|
||||||
help
|
|
||||||
GPIO number for Load switch.
|
|
||||||
|
|
||||||
config GPIO_TRIGGER_POWER
|
|
||||||
int "Trigger power GPIO Num"
|
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
|
||||||
default 2
|
default 2
|
||||||
help
|
help
|
||||||
GPIO number for Trigger.
|
GPIO number for Load switch.
|
||||||
|
|
||||||
config GPIO_TRIGGER_RESET
|
config EXPANDER_GPIO_SW_5V
|
||||||
int "Trigger reset GPIO Num"
|
int "5v Load Switch GPIO Num"
|
||||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
default 3
|
default 3
|
||||||
|
help
|
||||||
|
GPIO number for Load switch.
|
||||||
|
|
||||||
|
config EXPANDER_GPIO_TRIGGER_POWER
|
||||||
|
int "Trigger power GPIO Num"
|
||||||
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
|
default 0
|
||||||
help
|
help
|
||||||
GPIO number for Trigger.
|
GPIO number for Trigger.
|
||||||
|
|
||||||
|
config EXPANDER_GPIO_TRIGGER_RESET
|
||||||
|
int "Trigger reset GPIO Num"
|
||||||
|
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||||
|
default 1
|
||||||
|
help
|
||||||
|
GPIO number for Trigger.
|
||||||
|
|
||||||
|
config TRIGGER_POWER_DELAY_MS
|
||||||
|
int "Trigger reset GPIO Num"
|
||||||
|
range 100 5000
|
||||||
|
default 3000
|
||||||
|
help
|
||||||
|
Reset delay ms.
|
||||||
|
|
||||||
|
config TRIGGER_RESET_DELAY_MS
|
||||||
|
int "Trigger reset GPIO Num"
|
||||||
|
range 100 5000
|
||||||
|
default 1000
|
||||||
|
help
|
||||||
|
Reset delay ms.
|
||||||
endmenu
|
endmenu
|
||||||
endmenu
|
endmenu
|
||||||
@@ -1,48 +1,37 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/param.h>
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "driver/uart.h"
|
#include "i2cdev.h"
|
||||||
#include "esp_http_server.h"
|
|
||||||
#include "indicator.h"
|
#include "indicator.h"
|
||||||
#include "nconfig.h"
|
#include "nconfig.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
|
|
||||||
#include "lwip/err.h"
|
void app_main(void)
|
||||||
#include "lwip/sockets.h"
|
{
|
||||||
#include "lwip/sys.h"
|
ESP_ERROR_CHECK(i2cdev_init());;
|
||||||
|
|
||||||
static const char *TAG = "odroid-remote";
|
|
||||||
|
|
||||||
void app_main(void) {
|
|
||||||
init_led();
|
init_led();
|
||||||
led_set(LED_BLU, BLINK_TRIPLE);
|
led_set(LED_BLU, BLINK_TRIPLE);
|
||||||
led_off(LED_BLU);
|
led_off(LED_BLU);
|
||||||
|
|
||||||
// NVS 초기화
|
|
||||||
esp_err_t ret = nvs_flash_init();
|
esp_err_t ret = nvs_flash_init();
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||||
|
{
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
ret = nvs_flash_init();
|
ret = nvs_flash_init();
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
// 네트워크 초기화
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
ESP_ERROR_CHECK(init_nconfig());
|
ESP_ERROR_CHECK(init_nconfig());
|
||||||
|
|
||||||
// WiFi 연결
|
|
||||||
wifi_connect();
|
wifi_connect();
|
||||||
sync_time();
|
sync_time();
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
espressif/led_indicator: ^1.1.1
|
espressif/led_indicator: ^1.1.1
|
||||||
joltwallet/littlefs: ==1.20.1
|
joltwallet/littlefs: ==1.20.1
|
||||||
|
esp-idf-lib/ina3221: ^1.1.7
|
||||||
|
esp-idf-lib/pca9557: ^1.0.7
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
#include "ina226.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <esp_err.h>
|
|
||||||
|
|
||||||
#define INA226_REG_CONFIG (0x00)
|
|
||||||
#define INA226_REG_SHUNT_VOLTAGE (0x01)
|
|
||||||
#define INA226_REG_BUS_VOLTAGE (0x02)
|
|
||||||
#define INA226_REG_POWER (0x03)
|
|
||||||
#define INA226_REG_CURRENT (0x04)
|
|
||||||
#define INA226_REG_CALIBRATION (0x05)
|
|
||||||
#define INA226_REG_ALERT_MASK (0x06)
|
|
||||||
#define INA226_REG_ALERT_LIMIT (0x07)
|
|
||||||
#define INA226_REG_MANUFACTURER_ID (0xFE)
|
|
||||||
#define INA226_REG_DIE_ID (0xFF)
|
|
||||||
|
|
||||||
#define INA226_CFG_AVERAGING_OFFSET 9
|
|
||||||
#define INA226_CFG_BUS_VOLTAGE_OFFSET 6
|
|
||||||
#define INA226_CFG_SHUNT_VOLTAGE_OFFSET 3
|
|
||||||
|
|
||||||
static esp_err_t ina226_read_reg(ina226_t *handle, uint8_t reg_addr, uint16_t *data, size_t len)
|
|
||||||
{
|
|
||||||
return i2c_master_transmit_receive(handle->dev_handle, ®_addr, 1, (uint8_t *)data, len, handle->timeout_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t ina226_write_reg(ina226_t *handle, uint8_t reg_addr, uint16_t value)
|
|
||||||
{
|
|
||||||
uint8_t write_buf[3] = {reg_addr, value >> 8, value & 0xFF};
|
|
||||||
return i2c_master_transmit(handle->dev_handle, write_buf, sizeof(write_buf), handle->timeout_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_manufacturer_id(ina226_t *device, uint16_t *manufacturer_id)
|
|
||||||
{
|
|
||||||
return ina226_read_reg(device, INA226_REG_MANUFACTURER_ID, manufacturer_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_die_id(ina226_t *device, uint16_t *die_id)
|
|
||||||
{
|
|
||||||
return ina226_read_reg(device, INA226_REG_DIE_ID, die_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_shunt_voltage(ina226_t *device, float *voltage)
|
|
||||||
{
|
|
||||||
uint8_t data[2];
|
|
||||||
esp_err_t err = ina226_read_reg(device, INA226_REG_SHUNT_VOLTAGE, (uint16_t*)data, 2);
|
|
||||||
*voltage = (float) (data[0] << 8 | data[1]) * 2.5e-6f; /* fixed to 2.5 uV */
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_bus_voltage(ina226_t *device, float *voltage)
|
|
||||||
{
|
|
||||||
uint8_t data[2];
|
|
||||||
esp_err_t err = ina226_read_reg(device, INA226_REG_BUS_VOLTAGE, (uint16_t*)data, 2);
|
|
||||||
*voltage = (float) (data[0] << 8 | data[1]) * 0.00125f;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_current(ina226_t *device, float *current)
|
|
||||||
{
|
|
||||||
uint8_t data[2];
|
|
||||||
esp_err_t err = ina226_read_reg(device, INA226_REG_CURRENT, (uint16_t*)data, 2);
|
|
||||||
*current = ((float) (data[0] << 8 | data[1])) * device->current_lsb;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_power(ina226_t *device, float *power)
|
|
||||||
{
|
|
||||||
uint8_t data[2];
|
|
||||||
esp_err_t err = ina226_read_reg(device, INA226_REG_POWER, (uint16_t*)data, 2);
|
|
||||||
*power = (float) (data[0] << 8 | data[1]) * device->power_lsb;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_init(ina226_t *device, i2c_master_dev_handle_t dev_handle, const ina226_config_t *config)
|
|
||||||
{
|
|
||||||
esp_err_t err;
|
|
||||||
device->timeout_ms = config->timeout_ms;
|
|
||||||
device->dev_handle = dev_handle;
|
|
||||||
uint16_t bitmask = 0;
|
|
||||||
bitmask |= (config->averages << INA226_CFG_AVERAGING_OFFSET);
|
|
||||||
bitmask |= (config->bus_conv_time << INA226_CFG_BUS_VOLTAGE_OFFSET);
|
|
||||||
bitmask |= (config->shunt_conv_time << INA226_CFG_SHUNT_VOLTAGE_OFFSET);
|
|
||||||
bitmask |= config->mode;
|
|
||||||
err = ina226_write_reg(device, INA226_REG_CONFIG, bitmask);
|
|
||||||
if(err != ESP_OK) return err;
|
|
||||||
|
|
||||||
/* write calibration*/
|
|
||||||
float minimum_lsb = config->max_current / 32767;
|
|
||||||
float current_lsb = (uint16_t)(minimum_lsb * 100000000);
|
|
||||||
current_lsb /= 100000000;
|
|
||||||
current_lsb /= 0.0001;
|
|
||||||
current_lsb = ceil(current_lsb);
|
|
||||||
current_lsb *= 0.0001;
|
|
||||||
device->current_lsb = current_lsb;
|
|
||||||
device->power_lsb = current_lsb * 25;
|
|
||||||
uint16_t calibration_value = (uint16_t)((0.00512) / (current_lsb * config->r_shunt));
|
|
||||||
err = ina226_write_reg(device, INA226_REG_CALIBRATION, calibration_value);
|
|
||||||
if(err != ESP_OK) return err;
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_get_alert_mask(ina226_t *device, ina226_alert_t *alert_mask)
|
|
||||||
{
|
|
||||||
return ina226_read_reg(device, INA226_REG_ALERT_MASK, (uint16_t *)alert_mask, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_set_alert_mask(ina226_t *device, ina226_alert_t alert_mask)
|
|
||||||
{
|
|
||||||
return ina226_write_reg(device, INA226_REG_ALERT_MASK, (uint16_t)alert_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ina226_set_alert_limit(ina226_t *device, float voltage)
|
|
||||||
{
|
|
||||||
return ina226_write_reg(device, INA226_REG_ALERT_LIMIT, (uint16_t)(voltage));
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
#ifndef _INA226_H_
|
|
||||||
#define _INA226_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "driver/i2c_master.h"
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
INA226_AVERAGES_1 = 0b000,
|
|
||||||
INA226_AVERAGES_4 = 0b001,
|
|
||||||
INA226_AVERAGES_16 = 0b010,
|
|
||||||
INA226_AVERAGES_64 = 0b011,
|
|
||||||
INA226_AVERAGES_128 = 0b100,
|
|
||||||
INA226_AVERAGES_256 = 0b101,
|
|
||||||
INA226_AVERAGES_512 = 0b110,
|
|
||||||
INA226_AVERAGES_1024 = 0b111
|
|
||||||
} ina226_averages_t;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
INA226_BUS_CONV_TIME_140_US = 0b000,
|
|
||||||
INA226_BUS_CONV_TIME_204_US = 0b001,
|
|
||||||
INA226_BUS_CONV_TIME_332_US = 0b010,
|
|
||||||
INA226_BUS_CONV_TIME_588_US = 0b011,
|
|
||||||
INA226_BUS_CONV_TIME_1100_US = 0b100,
|
|
||||||
INA226_BUS_CONV_TIME_2116_US = 0b101,
|
|
||||||
INA226_BUS_CONV_TIME_4156_US = 0b110,
|
|
||||||
INA226_BUS_CONV_TIME_8244_US = 0b111
|
|
||||||
} ina226_bus_conv_time_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
INA226_SHUNT_CONV_TIME_140_US = 0b000,
|
|
||||||
INA226_SHUNT_CONV_TIME_204_US = 0b001,
|
|
||||||
INA226_SHUNT_CONV_TIME_332_US = 0b010,
|
|
||||||
INA226_SHUNT_CONV_TIME_588_US = 0b011,
|
|
||||||
INA226_SHUNT_CONV_TIME_1100_US = 0b100,
|
|
||||||
INA226_SHUNT_CONV_TIME_2116_US = 0b101,
|
|
||||||
INA226_SHUNT_CONV_TIME_4156_US = 0b110,
|
|
||||||
INA226_SHUNT_CONV_TIME_8244_US = 0b111
|
|
||||||
} ina226_shunt_conv_time_t;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
|
|
||||||
INA226_MODE_POWER_DOWN = 0b000,
|
|
||||||
INA226_MODE_SHUNT_TRIG = 0b001,
|
|
||||||
INA226_MODE_BUS_TRIG = 0b010,
|
|
||||||
INA226_MODE_SHUNT_BUS_TRIG = 0b011,
|
|
||||||
INA226_MODE_ADC_OFF = 0b100,
|
|
||||||
INA226_MODE_SHUNT_CONT = 0b101,
|
|
||||||
INA226_MODE_BUS_CONT = 0b110,
|
|
||||||
INA226_MODE_SHUNT_BUS_CONT = 0b111,
|
|
||||||
} ina226_mode_t;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
INA226_ALERT_SHUNT_OVER_VOLTAGE = 0xf,
|
|
||||||
INA226_ALERT_SHUNT_UNDER_VOLTAGE = 0xe,
|
|
||||||
INA226_ALERT_BUS_OVER_VOLTAGE = 0xd,
|
|
||||||
INA226_ALERT_BUS_UNDER_VOLTAGE = 0xc,
|
|
||||||
INA226_ALERT_POWER_OVER_LIMIT = 0xb,
|
|
||||||
INA226_ALERT_CONVERSION_READY = 0xa,
|
|
||||||
INA226_ALERT_FUNCTION_FLAG = 0x4,
|
|
||||||
INA226_ALERT_CONVERSION_READY_FLAG = 0x3,
|
|
||||||
INA226_ALERT_MATH_OVERFLOW_FLAG = 0x2,
|
|
||||||
INA226_ALERT_POLARITY = 0x1,
|
|
||||||
INA226_ALERT_LATCH_ENABLE = 0x0
|
|
||||||
} ina226_alert_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
i2c_port_t i2c_port;
|
|
||||||
int i2c_addr;
|
|
||||||
int timeout_ms;
|
|
||||||
ina226_averages_t averages;
|
|
||||||
ina226_bus_conv_time_t bus_conv_time;
|
|
||||||
ina226_shunt_conv_time_t shunt_conv_time;
|
|
||||||
ina226_mode_t mode;
|
|
||||||
float r_shunt; /* ohm */
|
|
||||||
float max_current; /* amps */
|
|
||||||
} ina226_config_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
i2c_master_dev_handle_t dev_handle;
|
|
||||||
int timeout_ms;
|
|
||||||
float current_lsb;
|
|
||||||
float power_lsb;
|
|
||||||
} ina226_t;
|
|
||||||
|
|
||||||
esp_err_t ina226_get_manufacturer_id(ina226_t *device, uint16_t *manufacturer_id);
|
|
||||||
esp_err_t ina226_get_die_id(ina226_t *device, uint16_t *die_id);
|
|
||||||
esp_err_t ina226_get_shunt_voltage(ina226_t *device, float *voltage);
|
|
||||||
esp_err_t ina226_get_bus_voltage(ina226_t *device, float *voltage);
|
|
||||||
esp_err_t ina226_get_current(ina226_t *device, float *current);
|
|
||||||
esp_err_t ina226_get_power(ina226_t *device, float *power);
|
|
||||||
esp_err_t ina226_get_alert_mask(ina226_t *device, ina226_alert_t *alert_mask);
|
|
||||||
esp_err_t ina226_set_alert_mask(ina226_t *device, ina226_alert_t alert_mask);
|
|
||||||
esp_err_t ina226_set_alert_limit(ina226_t *device, float voltage);
|
|
||||||
esp_err_t ina226_init(ina226_t *device, i2c_master_dev_handle_t dev_handle, const ina226_config_t *config);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -65,7 +65,7 @@ void init_led(void)
|
|||||||
led_indicator_ledc_config_t ledc_config = {0};
|
led_indicator_ledc_config_t ledc_config = {0};
|
||||||
led_indicator_config_t config = {0};
|
led_indicator_config_t config = {0};
|
||||||
|
|
||||||
ledc_config.is_active_level_high = true;
|
ledc_config.is_active_level_high = false;
|
||||||
ledc_config.timer_inited = false;
|
ledc_config.timer_inited = false;
|
||||||
ledc_config.timer_num = LEDC_TIMER_0;
|
ledc_config.timer_num = LEDC_TIMER_0;
|
||||||
ledc_config.gpio_num = LED_STATUS_GPIO;
|
ledc_config.gpio_num = LED_STATUS_GPIO;
|
||||||
@@ -78,7 +78,7 @@ void init_led(void)
|
|||||||
|
|
||||||
led_handle[LED_RED] = led_indicator_create(&config);
|
led_handle[LED_RED] = led_indicator_create(&config);
|
||||||
|
|
||||||
ledc_config.is_active_level_high = true;
|
ledc_config.is_active_level_high = false;
|
||||||
ledc_config.timer_inited = false;
|
ledc_config.timer_inited = false;
|
||||||
ledc_config.timer_num = LEDC_TIMER_0;
|
ledc_config.timer_num = LEDC_TIMER_0;
|
||||||
ledc_config.gpio_num = LED_WIFI_GPIO;
|
ledc_config.gpio_num = LED_WIFI_GPIO;
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ const static char *keys[NCONFIG_TYPE_MAX] = {
|
|||||||
[UART_BAUD_RATE] = "baudrate",
|
[UART_BAUD_RATE] = "baudrate",
|
||||||
};
|
};
|
||||||
|
|
||||||
struct default_value {
|
struct default_value
|
||||||
|
{
|
||||||
enum nconfig_type type;
|
enum nconfig_type type;
|
||||||
const char* value;
|
const char* value;
|
||||||
};
|
};
|
||||||
@@ -48,13 +49,15 @@ esp_err_t init_nconfig()
|
|||||||
esp_err_t ret = nvs_open(NCONFIG_NVS_NAMESPACE, NVS_READWRITE, &handle);
|
esp_err_t ret = nvs_open(NCONFIG_NVS_NAMESPACE, NVS_READWRITE, &handle);
|
||||||
if (ret != ESP_OK) return ret;
|
if (ret != ESP_OK) return ret;
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(default_values) / sizeof(default_values[0]); ++i) {
|
for (int i = 0; i < sizeof(default_values) / sizeof(default_values[0]); ++i)
|
||||||
|
{
|
||||||
// check key is not exist or value is null
|
// check key is not exist or value is null
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
nconfig_get_str_len(default_values[i].type, &len);
|
nconfig_get_str_len(default_values[i].type, &len);
|
||||||
if (len <= 1) // nconfig_get_str_len return err or value is '\0'
|
if (len <= 1) // nconfig_get_str_len return err or value is '\0'
|
||||||
{
|
{
|
||||||
if (nconfig_write(default_values[i].type, default_values[i].value) != ESP_OK) // if nconfig write fail, system panic
|
if (nconfig_write(default_values[i].type, default_values[i].value) != ESP_OK)
|
||||||
|
// if nconfig write fail, system panic
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,44 +4,14 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "sw.h"
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "esp_timer.h"
|
|
||||||
|
|
||||||
#define GPIO_12V_SWITCH CONFIG_GPIO_SW_12V
|
|
||||||
#define GPIO_5V_SWITCH CONFIG_GPIO_SW_5V
|
|
||||||
#define GPIO_POWER_TRIGGER CONFIG_GPIO_TRIGGER_POWER
|
|
||||||
#define GPIO_RESET_TRIGGER CONFIG_GPIO_TRIGGER_RESET
|
|
||||||
|
|
||||||
static bool status_12v_on = false;
|
|
||||||
static bool status_5v_on = false;
|
|
||||||
static SemaphoreHandle_t state_mutex;
|
|
||||||
static esp_timer_handle_t power_trigger_timer;
|
|
||||||
static esp_timer_handle_t reset_trigger_timer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 타이머 만료 시 GPIO를 다시 HIGH로 설정하는 콜백 함수
|
|
||||||
*/
|
|
||||||
static void trigger_off_callback(void* arg)
|
|
||||||
{
|
|
||||||
gpio_num_t gpio_pin = (int) arg;
|
|
||||||
gpio_set_level(gpio_pin, 1); // 핀을 다시 HIGH로 복구
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_gpio_switches()
|
|
||||||
{
|
|
||||||
gpio_set_level(GPIO_12V_SWITCH, status_12v_on);
|
|
||||||
gpio_set_level(GPIO_5V_SWITCH, status_5v_on);
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t control_get_handler(httpd_req_t* req)
|
static esp_err_t control_get_handler(httpd_req_t* req)
|
||||||
{
|
{
|
||||||
cJSON* root = cJSON_CreateObject();
|
cJSON* root = cJSON_CreateObject();
|
||||||
|
|
||||||
xSemaphoreTake(state_mutex, portMAX_DELAY);
|
cJSON_AddBoolToObject(root, "load_12v_on", get_main_load_switch());
|
||||||
cJSON_AddBoolToObject(root, "load_12v_on", status_12v_on);
|
cJSON_AddBoolToObject(root, "load_5v_on", get_usb_load_switch());
|
||||||
cJSON_AddBoolToObject(root, "load_5v_on", status_5v_on);
|
|
||||||
xSemaphoreGive(state_mutex);
|
|
||||||
|
|
||||||
char* json_string = cJSON_Print(root);
|
char* json_string = cJSON_Print(root);
|
||||||
httpd_resp_set_type(req, "application/json");
|
httpd_resp_set_type(req, "application/json");
|
||||||
@@ -58,14 +28,17 @@ static esp_err_t control_post_handler(httpd_req_t *req)
|
|||||||
char buf[128];
|
char buf[128];
|
||||||
int ret, remaining = req->content_len;
|
int ret, remaining = req->content_len;
|
||||||
|
|
||||||
if (remaining >= sizeof(buf)) {
|
if (remaining >= sizeof(buf))
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Request content too long");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Request content too long");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = httpd_req_recv(req, buf, remaining);
|
ret = httpd_req_recv(req, buf, remaining);
|
||||||
if (ret <= 0) {
|
if (ret <= 0)
|
||||||
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
|
{
|
||||||
|
if (ret == HTTPD_SOCK_ERR_TIMEOUT)
|
||||||
|
{
|
||||||
httpd_resp_send_408(req);
|
httpd_resp_send_408(req);
|
||||||
}
|
}
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -73,44 +46,23 @@ static esp_err_t control_post_handler(httpd_req_t *req)
|
|||||||
buf[ret] = '\0';
|
buf[ret] = '\0';
|
||||||
|
|
||||||
cJSON* root = cJSON_Parse(buf);
|
cJSON* root = cJSON_Parse(buf);
|
||||||
if (root == NULL) {
|
if (root == NULL)
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool state_changed = false;
|
|
||||||
xSemaphoreTake(state_mutex, portMAX_DELAY);
|
|
||||||
|
|
||||||
cJSON* item_12v = cJSON_GetObjectItem(root, "load_12v_on");
|
cJSON* item_12v = cJSON_GetObjectItem(root, "load_12v_on");
|
||||||
if (cJSON_IsBool(item_12v)) {
|
if (cJSON_IsBool(item_12v)) set_main_load_switch(cJSON_IsTrue(item_12v));
|
||||||
status_12v_on = cJSON_IsTrue(item_12v);
|
|
||||||
state_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON* item_5v = cJSON_GetObjectItem(root, "load_5v_on");
|
cJSON* item_5v = cJSON_GetObjectItem(root, "load_5v_on");
|
||||||
if (cJSON_IsBool(item_5v)) {
|
if (cJSON_IsBool(item_5v)) set_usb_load_switch(cJSON_IsTrue(item_5v));
|
||||||
status_5v_on = cJSON_IsTrue(item_5v);
|
|
||||||
state_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state_changed) {
|
|
||||||
update_gpio_switches();
|
|
||||||
}
|
|
||||||
xSemaphoreGive(state_mutex);
|
|
||||||
|
|
||||||
cJSON* power_trigger = cJSON_GetObjectItem(root, "power_trigger");
|
cJSON* power_trigger = cJSON_GetObjectItem(root, "power_trigger");
|
||||||
if (cJSON_IsTrue(power_trigger)) {
|
if (cJSON_IsTrue(power_trigger)) trig_power();
|
||||||
gpio_set_level(GPIO_POWER_TRIGGER, 0);
|
|
||||||
esp_timer_stop(power_trigger_timer); // Stop timer if it's already running
|
|
||||||
ESP_ERROR_CHECK(esp_timer_start_once(power_trigger_timer, 3000000)); // 3초
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON* reset_trigger = cJSON_GetObjectItem(root, "reset_trigger");
|
cJSON* reset_trigger = cJSON_GetObjectItem(root, "reset_trigger");
|
||||||
if (cJSON_IsTrue(reset_trigger)) {
|
if (cJSON_IsTrue(reset_trigger)) trig_reset();
|
||||||
gpio_set_level(GPIO_RESET_TRIGGER, 0);
|
|
||||||
esp_timer_stop(reset_trigger_timer); // Stop timer if it's already running
|
|
||||||
ESP_ERROR_CHECK(esp_timer_start_once(reset_trigger_timer, 3000000)); // 3초
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
|
|
||||||
@@ -118,50 +70,9 @@ static esp_err_t control_post_handler(httpd_req_t *req)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void control_module_init(void)
|
|
||||||
{
|
|
||||||
state_mutex = xSemaphoreCreateMutex();
|
|
||||||
|
|
||||||
gpio_config_t switch_conf = {
|
|
||||||
.pin_bit_mask = (1ULL << GPIO_12V_SWITCH) | (1ULL << GPIO_5V_SWITCH),
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
|
||||||
};
|
|
||||||
gpio_config(&switch_conf);
|
|
||||||
update_gpio_switches();
|
|
||||||
|
|
||||||
gpio_config_t trigger_conf = {
|
|
||||||
.pin_bit_mask = (1ULL << GPIO_POWER_TRIGGER) | (1ULL << GPIO_RESET_TRIGGER),
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
|
||||||
};
|
|
||||||
gpio_config(&trigger_conf);
|
|
||||||
gpio_set_level(GPIO_POWER_TRIGGER, 1);
|
|
||||||
gpio_set_level(GPIO_RESET_TRIGGER, 1);
|
|
||||||
|
|
||||||
const esp_timer_create_args_t power_timer_args = {
|
|
||||||
.callback = &trigger_off_callback,
|
|
||||||
.arg = (void*) GPIO_POWER_TRIGGER,
|
|
||||||
.name = "power_trigger_off"
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(esp_timer_create(&power_timer_args, &power_trigger_timer));
|
|
||||||
|
|
||||||
const esp_timer_create_args_t reset_timer_args = {
|
|
||||||
.callback = &trigger_off_callback,
|
|
||||||
.arg = (void*) GPIO_RESET_TRIGGER,
|
|
||||||
.name = "reset_trigger_off"
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(esp_timer_create(&reset_timer_args, &reset_trigger_timer));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_control_endpoint(httpd_handle_t server)
|
void register_control_endpoint(httpd_handle_t server)
|
||||||
{
|
{
|
||||||
control_module_init();
|
init_sw();
|
||||||
httpd_uri_t get_uri = {
|
httpd_uri_t get_uri = {
|
||||||
.uri = "/api/control",
|
.uri = "/api/control",
|
||||||
.method = HTTP_GET,
|
.method = HTTP_GET,
|
||||||
@@ -177,5 +88,4 @@ void register_control_endpoint(httpd_handle_t server)
|
|||||||
.user_ctx = NULL
|
.user_ctx = NULL
|
||||||
};
|
};
|
||||||
httpd_register_uri_handler(server, &post_uri);
|
httpd_register_uri_handler(server, &post_uri);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,9 +7,10 @@
|
|||||||
#include "esp_littlefs.h"
|
#include "esp_littlefs.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
static const char* TAG = "DATALOG";
|
static const char* TAG = "datalog";
|
||||||
static const char* LOG_FILE_PATH = "/littlefs/datalog.csv";
|
static const char* LOG_FILE_PATH = "/littlefs/datalog.csv";
|
||||||
#define MAX_LOG_SIZE (512 * 1024)
|
|
||||||
|
#define MAX_LOG_SIZE (700 * 1024)
|
||||||
|
|
||||||
void datalog_init(void)
|
void datalog_init(void)
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,7 @@ void datalog_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t total = 0, used = 0;
|
size_t total = 0, used = 0;
|
||||||
ret = esp_littlefs_info(NULL, &total, &used);
|
ret = esp_littlefs_info(conf.partition_label, &total, &used);
|
||||||
if (ret != ESP_OK)
|
if (ret != ESP_OK)
|
||||||
{
|
{
|
||||||
ESP_LOGE(TAG, "Failed to get LittleFS partition information (%s)", esp_err_to_name(ret));
|
ESP_LOGE(TAG, "Failed to get LittleFS partition information (%s)", esp_err_to_name(ret));
|
||||||
@@ -64,19 +65,20 @@ void datalog_init(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Add header
|
// Add header for 3 channels
|
||||||
fprintf(f_write, "timestamp,voltage,current,power\n");
|
fprintf(f_write, "timestamp,usb_voltage,usb_current,usb_power,main_voltage,main_current,main_power,vin_voltage,vin_current,vin_power\n");
|
||||||
fclose(f_write);
|
fclose(f_write);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Here we could check if the header is correct, but for now we assume it is.
|
||||||
ESP_LOGI(TAG, "Log file found.");
|
ESP_LOGI(TAG, "Log file found.");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void datalog_add(uint32_t timestamp, float voltage, float current, float power)
|
void datalog_add(uint32_t timestamp, const channel_data_t* channel_data)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(LOG_FILE_PATH, &st) == 0)
|
if (stat(LOG_FILE_PATH, &st) == 0)
|
||||||
@@ -139,7 +141,11 @@ void datalog_add(uint32_t timestamp, float voltage, float current, float power)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(f, "%lu,%.3f,%.3f,%.3f\n", timestamp, voltage, current, power);
|
fprintf(f, "%lu", timestamp);
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
fprintf(f, ",%.3f,%.3f,%.3f", channel_data[i].voltage, channel_data[i].current, channel_data[i].power);
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,16 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define NUM_CHANNELS 3
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float voltage;
|
||||||
|
float current;
|
||||||
|
float power;
|
||||||
|
} channel_data_t;
|
||||||
|
|
||||||
void datalog_init(void);
|
void datalog_init(void);
|
||||||
void datalog_add(uint32_t timestamp, float voltage, float current, float power);
|
void datalog_add(uint32_t timestamp, const channel_data_t* channel_data);
|
||||||
const char* datalog_get_path(void);
|
const char* datalog_get_path(void);
|
||||||
|
|
||||||
#endif /* MAIN_SERVICE_DATALOG_H_ */
|
#endif /* MAIN_SERVICE_DATALOG_H_ */
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
@@ -17,39 +15,78 @@
|
|||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
#include "datalog.h"
|
#include "datalog.h"
|
||||||
|
#include "ina3221.h"
|
||||||
|
|
||||||
#define INA226_SDA CONFIG_GPIO_INA226_SDA
|
#define PM_SDA CONFIG_I2C_GPIO_SDA
|
||||||
#define INA226_SCL CONFIG_GPIO_INA226_SCL
|
#define PM_SCL CONFIG_I2C_GPIO_SCL
|
||||||
|
|
||||||
ina226_t ina;
|
const char* channel_names[] = {
|
||||||
i2c_master_bus_handle_t bus_handle;
|
"USB",
|
||||||
i2c_master_dev_handle_t dev_handle;
|
"MAIN",
|
||||||
|
"VIN"
|
||||||
|
};
|
||||||
|
|
||||||
|
ina3221_t ina3221 =
|
||||||
|
{
|
||||||
|
/* shunt values are 100 mOhm for each channel */
|
||||||
|
.shunt = {
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
},
|
||||||
|
.mask.mask_register = INA3221_DEFAULT_MASK,
|
||||||
|
.i2c_dev = {0},
|
||||||
|
.config = {
|
||||||
|
.mode = true, // mode selection
|
||||||
|
.esht = true, // shunt enable
|
||||||
|
.ebus = true, // bus enable
|
||||||
|
.ch1 = true, // channel 1 enable
|
||||||
|
.ch2 = true, // channel 2 enable
|
||||||
|
.ch3 = true, // channel 3 enable
|
||||||
|
.avg = INA3221_AVG_64, // 64 samples average
|
||||||
|
.vbus = INA3221_CT_2116, // 2ms by channel (bus)
|
||||||
|
.vsht = INA3221_CT_2116, // 2ms by channel (shunt)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Timer callback function to read sensor data
|
// Timer callback function to read sensor data
|
||||||
static void sensor_timer_callback(void* arg)
|
static void sensor_timer_callback(void* arg)
|
||||||
{
|
{
|
||||||
// Generate random sensor data
|
|
||||||
float voltage = 0;
|
|
||||||
float current = 0;
|
|
||||||
float power = 0;
|
|
||||||
|
|
||||||
ina226_get_bus_voltage(&ina, &voltage);
|
|
||||||
ina226_get_power(&ina, &power);
|
|
||||||
ina226_get_current(&ina, ¤t);
|
|
||||||
|
|
||||||
// Get system uptime
|
// Get system uptime
|
||||||
int64_t uptime_us = esp_timer_get_time();
|
int64_t uptime_us = esp_timer_get_time();
|
||||||
uint32_t uptime_sec = (uint32_t)(uptime_us / 1000000);
|
uint32_t uptime_sec = (uint32_t)(uptime_us / 1000000);
|
||||||
uint32_t timestamp = (uint32_t)time(NULL);
|
uint32_t timestamp = (uint32_t)time(NULL);
|
||||||
|
|
||||||
datalog_add(timestamp, voltage, current, power);
|
channel_data_t channel_data[NUM_CHANNELS];
|
||||||
|
|
||||||
// Create JSON object with sensor data
|
// Create JSON object with sensor data
|
||||||
cJSON* root = cJSON_CreateObject();
|
cJSON* root = cJSON_CreateObject();
|
||||||
|
for (uint8_t i = 0; i < INA3221_BUS_NUMBER; i++)
|
||||||
|
{
|
||||||
|
float voltage, current, power;
|
||||||
|
|
||||||
|
ina3221_get_bus_voltage(&ina3221, i, &voltage);
|
||||||
|
ina3221_get_shunt_value(&ina3221, i, NULL, ¤t);
|
||||||
|
|
||||||
|
current /= 1000.0f; // mA to A
|
||||||
|
power = voltage * current;
|
||||||
|
|
||||||
|
// Populate data for datalog
|
||||||
|
channel_data[i].voltage = voltage;
|
||||||
|
channel_data[i].current = current;
|
||||||
|
channel_data[i].power = power;
|
||||||
|
|
||||||
|
// Populate data for websocket
|
||||||
|
cJSON* v = cJSON_AddObjectToObject(root, channel_names[i]);
|
||||||
|
cJSON_AddNumberToObject(v, "voltage", voltage);
|
||||||
|
cJSON_AddNumberToObject(v, "current", current);
|
||||||
|
cJSON_AddNumberToObject(v, "power", power);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add data to log file
|
||||||
|
datalog_add(timestamp, channel_data);
|
||||||
|
|
||||||
cJSON_AddStringToObject(root, "type", "sensor_data");
|
cJSON_AddStringToObject(root, "type", "sensor_data");
|
||||||
cJSON_AddNumberToObject(root, "voltage", voltage);
|
|
||||||
cJSON_AddNumberToObject(root, "current", current);
|
|
||||||
cJSON_AddNumberToObject(root, "power", power);
|
|
||||||
cJSON_AddNumberToObject(root, "timestamp", timestamp);
|
cJSON_AddNumberToObject(root, "timestamp", timestamp);
|
||||||
cJSON_AddNumberToObject(root, "uptime_sec", uptime_sec);
|
cJSON_AddNumberToObject(root, "uptime_sec", uptime_sec);
|
||||||
|
|
||||||
@@ -62,58 +99,29 @@ static void status_wifi_callback(void *arg)
|
|||||||
wifi_ap_record_t ap_info;
|
wifi_ap_record_t ap_info;
|
||||||
cJSON* root = cJSON_CreateObject();
|
cJSON* root = cJSON_CreateObject();
|
||||||
|
|
||||||
if (wifi_get_current_ap_info(&ap_info) == ESP_OK) {
|
if (wifi_get_current_ap_info(&ap_info) == ESP_OK)
|
||||||
|
{
|
||||||
cJSON_AddStringToObject(root, "type", "wifi_status");
|
cJSON_AddStringToObject(root, "type", "wifi_status");
|
||||||
cJSON_AddBoolToObject(root, "connected", true);
|
cJSON_AddBoolToObject(root, "connected", true);
|
||||||
cJSON_AddStringToObject(root, "ssid", (const char*)ap_info.ssid);
|
cJSON_AddStringToObject(root, "ssid", (const char*)ap_info.ssid);
|
||||||
cJSON_AddNumberToObject(root, "rssi", ap_info.rssi);
|
cJSON_AddNumberToObject(root, "rssi", ap_info.rssi);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cJSON_AddBoolToObject(root, "connected", false);
|
cJSON_AddBoolToObject(root, "connected", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
push_data_to_ws(root);
|
push_data_to_ws(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
ina226_config_t ina_config = {
|
|
||||||
.i2c_port = I2C_NUM_0,
|
|
||||||
.i2c_addr = 0x40,
|
|
||||||
.timeout_ms = 100,
|
|
||||||
.averages = INA226_AVERAGES_16,
|
|
||||||
.bus_conv_time = INA226_BUS_CONV_TIME_1100_US,
|
|
||||||
.shunt_conv_time = INA226_SHUNT_CONV_TIME_1100_US,
|
|
||||||
.mode = INA226_MODE_SHUNT_BUS_CONT,
|
|
||||||
.r_shunt = 0.01f,
|
|
||||||
.max_current = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
static void init_ina226()
|
|
||||||
{
|
|
||||||
i2c_master_bus_config_t bus_config = {
|
|
||||||
.i2c_port = I2C_NUM_0,
|
|
||||||
.sda_io_num = (gpio_num_t) INA226_SDA,
|
|
||||||
.scl_io_num = (gpio_num_t) INA226_SCL,
|
|
||||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
|
||||||
.glitch_ignore_cnt = 7,
|
|
||||||
.flags.enable_internal_pullup = true,
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &bus_handle));
|
|
||||||
|
|
||||||
i2c_device_config_t dev_config = {
|
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
||||||
.device_address = 0x40,
|
|
||||||
.scl_speed_hz = 400000,
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_config, &dev_handle));
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(ina226_init(&ina, dev_handle, &ina_config));
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_timer_handle_t sensor_timer;
|
static esp_timer_handle_t sensor_timer;
|
||||||
static esp_timer_handle_t wifi_status_timer;
|
static esp_timer_handle_t wifi_status_timer;
|
||||||
|
|
||||||
void init_status_monitor()
|
void init_status_monitor()
|
||||||
{
|
{
|
||||||
init_ina226();
|
ESP_ERROR_CHECK(ina3221_init_desc(&ina3221, 0x40, 0, PM_SDA, PM_SCL));
|
||||||
|
|
||||||
|
// logger
|
||||||
datalog_init();
|
datalog_init();
|
||||||
|
|
||||||
// Timer configuration
|
// Timer configuration
|
||||||
|
|||||||
@@ -9,15 +9,14 @@
|
|||||||
|
|
||||||
#include "esp_http_server.h"
|
#include "esp_http_server.h"
|
||||||
|
|
||||||
// 버퍼에 저장할 데이터의 개수
|
|
||||||
#define SENSOR_BUFFER_SIZE 100
|
#define SENSOR_BUFFER_SIZE 100
|
||||||
|
|
||||||
// 단일 센서 데이터를 저장하기 위한 구조체
|
typedef struct
|
||||||
typedef struct {
|
{
|
||||||
float voltage;
|
float voltage;
|
||||||
float current;
|
float current;
|
||||||
float power;
|
float power;
|
||||||
uint32_t timestamp; // 데이터를 읽은 시간 (부팅 후 ms)
|
uint32_t timestamp;
|
||||||
} sensor_data_t;
|
} sensor_data_t;
|
||||||
|
|
||||||
void init_status_monitor();
|
void init_status_monitor();
|
||||||
|
|||||||
@@ -16,33 +16,42 @@ static esp_err_t setting_get_handler(httpd_req_t *req)
|
|||||||
cJSON* root = cJSON_CreateObject();
|
cJSON* root = cJSON_CreateObject();
|
||||||
|
|
||||||
char mode_buf[16];
|
char mode_buf[16];
|
||||||
if (nconfig_read(WIFI_MODE, mode_buf, sizeof(mode_buf)) == ESP_OK) {
|
if (nconfig_read(WIFI_MODE, mode_buf, sizeof(mode_buf)) == ESP_OK)
|
||||||
|
{
|
||||||
cJSON_AddStringToObject(root, "mode", mode_buf);
|
cJSON_AddStringToObject(root, "mode", mode_buf);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cJSON_AddStringToObject(root, "mode", "sta"); // Default to sta
|
cJSON_AddStringToObject(root, "mode", "sta"); // Default to sta
|
||||||
}
|
}
|
||||||
|
|
||||||
char net_type_buf[16];
|
char net_type_buf[16];
|
||||||
if (nconfig_read(NETIF_TYPE, net_type_buf, sizeof(net_type_buf)) == ESP_OK) {
|
if (nconfig_read(NETIF_TYPE, net_type_buf, sizeof(net_type_buf)) == ESP_OK)
|
||||||
|
{
|
||||||
cJSON_AddStringToObject(root, "net_type", net_type_buf);
|
cJSON_AddStringToObject(root, "net_type", net_type_buf);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cJSON_AddStringToObject(root, "net_type", "dhcp"); // Default to dhcp
|
cJSON_AddStringToObject(root, "net_type", "dhcp"); // Default to dhcp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add baudrate to the response
|
// Add baudrate to the response
|
||||||
char baud_buf[16];
|
char baud_buf[16];
|
||||||
if (nconfig_read(UART_BAUD_RATE, baud_buf, sizeof(baud_buf)) == ESP_OK) {
|
if (nconfig_read(UART_BAUD_RATE, baud_buf, sizeof(baud_buf)) == ESP_OK)
|
||||||
|
{
|
||||||
cJSON_AddStringToObject(root, "baudrate", baud_buf);
|
cJSON_AddStringToObject(root, "baudrate", baud_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wifi_get_current_ap_info(&ap_info) == ESP_OK) {
|
if (wifi_get_current_ap_info(&ap_info) == ESP_OK)
|
||||||
|
{
|
||||||
cJSON_AddBoolToObject(root, "connected", true);
|
cJSON_AddBoolToObject(root, "connected", true);
|
||||||
cJSON_AddStringToObject(root, "ssid", (const char*)ap_info.ssid);
|
cJSON_AddStringToObject(root, "ssid", (const char*)ap_info.ssid);
|
||||||
cJSON_AddNumberToObject(root, "rssi", ap_info.rssi);
|
cJSON_AddNumberToObject(root, "rssi", ap_info.rssi);
|
||||||
|
|
||||||
esp_netif_ip_info_t ip_info;
|
esp_netif_ip_info_t ip_info;
|
||||||
cJSON* ip_obj = cJSON_CreateObject();
|
cJSON* ip_obj = cJSON_CreateObject();
|
||||||
if (wifi_get_current_ip_info(&ip_info) == ESP_OK) {
|
if (wifi_get_current_ip_info(&ip_info) == ESP_OK)
|
||||||
|
{
|
||||||
char ip_str[16];
|
char ip_str[16];
|
||||||
esp_ip4addr_ntoa(&ip_info.ip, ip_str, sizeof(ip_str));
|
esp_ip4addr_ntoa(&ip_info.ip, ip_str, sizeof(ip_str));
|
||||||
cJSON_AddStringToObject(ip_obj, "ip", ip_str);
|
cJSON_AddStringToObject(ip_obj, "ip", ip_str);
|
||||||
@@ -54,17 +63,20 @@ static esp_err_t setting_get_handler(httpd_req_t *req)
|
|||||||
|
|
||||||
esp_netif_dns_info_t dns_info;
|
esp_netif_dns_info_t dns_info;
|
||||||
char dns_str[16];
|
char dns_str[16];
|
||||||
if (wifi_get_dns_info(ESP_NETIF_DNS_MAIN, &dns_info) == ESP_OK) {
|
if (wifi_get_dns_info(ESP_NETIF_DNS_MAIN, &dns_info) == ESP_OK)
|
||||||
|
{
|
||||||
esp_ip4addr_ntoa(&dns_info.ip.u_addr.ip4, dns_str, sizeof(dns_str));
|
esp_ip4addr_ntoa(&dns_info.ip.u_addr.ip4, dns_str, sizeof(dns_str));
|
||||||
cJSON_AddStringToObject(ip_obj, "dns1", dns_str);
|
cJSON_AddStringToObject(ip_obj, "dns1", dns_str);
|
||||||
}
|
}
|
||||||
if (wifi_get_dns_info(ESP_NETIF_DNS_BACKUP, &dns_info) == ESP_OK) {
|
if (wifi_get_dns_info(ESP_NETIF_DNS_BACKUP, &dns_info) == ESP_OK)
|
||||||
|
{
|
||||||
esp_ip4addr_ntoa(&dns_info.ip.u_addr.ip4, dns_str, sizeof(dns_str));
|
esp_ip4addr_ntoa(&dns_info.ip.u_addr.ip4, dns_str, sizeof(dns_str));
|
||||||
cJSON_AddStringToObject(ip_obj, "dns2", dns_str);
|
cJSON_AddStringToObject(ip_obj, "dns2", dns_str);
|
||||||
}
|
}
|
||||||
cJSON_AddItemToObject(root, "ip", ip_obj);
|
cJSON_AddItemToObject(root, "ip", ip_obj);
|
||||||
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
cJSON_AddBoolToObject(root, "connected", false);
|
cJSON_AddBoolToObject(root, "connected", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,14 +124,16 @@ static esp_err_t setting_post_handler(httpd_req_t *req)
|
|||||||
char buf[512];
|
char buf[512];
|
||||||
int received = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
int received = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
||||||
|
|
||||||
if (received <= 0) {
|
if (received <= 0)
|
||||||
|
{
|
||||||
if (received == HTTPD_SOCK_ERR_TIMEOUT) httpd_resp_send_408(req);
|
if (received == HTTPD_SOCK_ERR_TIMEOUT) httpd_resp_send_408(req);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
buf[received] = '\0';
|
buf[received] = '\0';
|
||||||
|
|
||||||
cJSON* root = cJSON_Parse(buf);
|
cJSON* root = cJSON_Parse(buf);
|
||||||
if (root == NULL) {
|
if (root == NULL)
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -129,40 +143,54 @@ static esp_err_t setting_post_handler(httpd_req_t *req)
|
|||||||
cJSON* ssid_item = cJSON_GetObjectItem(root, "ssid");
|
cJSON* ssid_item = cJSON_GetObjectItem(root, "ssid");
|
||||||
cJSON* baud_item = cJSON_GetObjectItem(root, "baudrate");
|
cJSON* baud_item = cJSON_GetObjectItem(root, "baudrate");
|
||||||
|
|
||||||
if (mode_item && cJSON_IsString(mode_item)) {
|
if (mode_item && cJSON_IsString(mode_item))
|
||||||
|
{
|
||||||
const char* mode = mode_item->valuestring;
|
const char* mode = mode_item->valuestring;
|
||||||
ESP_LOGI(TAG, "Received mode switch request: %s", mode);
|
ESP_LOGI(TAG, "Received mode switch request: %s", mode);
|
||||||
|
|
||||||
if (strcmp(mode, "sta") == 0 || strcmp(mode, "apsta") == 0) {
|
if (strcmp(mode, "sta") == 0 || strcmp(mode, "apsta") == 0)
|
||||||
if (strcmp(mode, "apsta") == 0) {
|
{
|
||||||
|
if (strcmp(mode, "apsta") == 0)
|
||||||
|
{
|
||||||
cJSON* ap_ssid_item = cJSON_GetObjectItem(root, "ap_ssid");
|
cJSON* ap_ssid_item = cJSON_GetObjectItem(root, "ap_ssid");
|
||||||
cJSON* ap_pass_item = cJSON_GetObjectItem(root, "ap_password");
|
cJSON* ap_pass_item = cJSON_GetObjectItem(root, "ap_password");
|
||||||
|
|
||||||
if (ap_ssid_item && cJSON_IsString(ap_ssid_item)) {
|
if (ap_ssid_item && cJSON_IsString(ap_ssid_item))
|
||||||
|
{
|
||||||
nconfig_write(AP_SSID, ap_ssid_item->valuestring);
|
nconfig_write(AP_SSID, ap_ssid_item->valuestring);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "AP SSID required for APSTA mode");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "AP SSID required for APSTA mode");
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ap_pass_item && cJSON_IsString(ap_pass_item)) {
|
if (ap_pass_item && cJSON_IsString(ap_pass_item))
|
||||||
|
{
|
||||||
nconfig_write(AP_PASSWORD, ap_pass_item->valuestring);
|
nconfig_write(AP_PASSWORD, ap_pass_item->valuestring);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
nconfig_delete(AP_PASSWORD); // Open network
|
nconfig_delete(AP_PASSWORD); // Open network
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_switch_mode(mode);
|
wifi_switch_mode(mode);
|
||||||
httpd_resp_sendstr(req, "{\"status\":\"mode_switch_initiated\"}");
|
httpd_resp_sendstr(req, "{\"status\":\"mode_switch_initiated\"}");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid mode");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid mode");
|
||||||
}
|
}
|
||||||
} else if (net_type_item && cJSON_IsString(net_type_item)) {
|
}
|
||||||
|
else if (net_type_item && cJSON_IsString(net_type_item))
|
||||||
|
{
|
||||||
const char* type = net_type_item->valuestring;
|
const char* type = net_type_item->valuestring;
|
||||||
ESP_LOGI(TAG, "Received network config: %s", type);
|
ESP_LOGI(TAG, "Received network config: %s", type);
|
||||||
|
|
||||||
if (strcmp(type, "static") == 0) {
|
if (strcmp(type, "static") == 0)
|
||||||
|
{
|
||||||
cJSON* ip_item = cJSON_GetObjectItem(root, "ip");
|
cJSON* ip_item = cJSON_GetObjectItem(root, "ip");
|
||||||
cJSON* gw_item = cJSON_GetObjectItem(root, "gateway");
|
cJSON* gw_item = cJSON_GetObjectItem(root, "gateway");
|
||||||
cJSON* sn_item = cJSON_GetObjectItem(root, "subnet");
|
cJSON* sn_item = cJSON_GetObjectItem(root, "subnet");
|
||||||
@@ -175,27 +203,36 @@ static esp_err_t setting_post_handler(httpd_req_t *req)
|
|||||||
const char* d1 = cJSON_IsString(d1_item) ? d1_item->valuestring : NULL;
|
const char* d1 = cJSON_IsString(d1_item) ? d1_item->valuestring : NULL;
|
||||||
const char* d2 = cJSON_IsString(d2_item) ? d2_item->valuestring : NULL;
|
const char* d2 = cJSON_IsString(d2_item) ? d2_item->valuestring : NULL;
|
||||||
|
|
||||||
if (ip && gw && sn && d1) {
|
if (ip && gw && sn && d1)
|
||||||
|
{
|
||||||
nconfig_write(NETIF_TYPE, "static");
|
nconfig_write(NETIF_TYPE, "static");
|
||||||
nconfig_write(NETIF_IP, ip);
|
nconfig_write(NETIF_IP, ip);
|
||||||
nconfig_write(NETIF_GATEWAY, gw);
|
nconfig_write(NETIF_GATEWAY, gw);
|
||||||
nconfig_write(NETIF_SUBNET, sn);
|
nconfig_write(NETIF_SUBNET, sn);
|
||||||
nconfig_write(NETIF_DNS1, d1);
|
nconfig_write(NETIF_DNS1, d1);
|
||||||
if (d2) nconfig_write(NETIF_DNS2, d2); else nconfig_delete(NETIF_DNS2);
|
if (d2) nconfig_write(NETIF_DNS2, d2);
|
||||||
|
else nconfig_delete(NETIF_DNS2);
|
||||||
|
|
||||||
wifi_use_static(ip, gw, sn, d1, d2);
|
wifi_use_static(ip, gw, sn, d1, d2);
|
||||||
httpd_resp_sendstr(req, "{\"status\":\"static_config_applied\"}");
|
httpd_resp_sendstr(req, "{\"status\":\"static_config_applied\"}");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Missing static IP fields");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Missing static IP fields");
|
||||||
}
|
}
|
||||||
} else if (strcmp(type, "dhcp") == 0) {
|
}
|
||||||
|
else if (strcmp(type, "dhcp") == 0)
|
||||||
|
{
|
||||||
nconfig_write(NETIF_TYPE, "dhcp");
|
nconfig_write(NETIF_TYPE, "dhcp");
|
||||||
wifi_use_dhcp();
|
wifi_use_dhcp();
|
||||||
httpd_resp_sendstr(req, "{\"status\":\"dhcp_config_applied\"}");
|
httpd_resp_sendstr(req, "{\"status\":\"dhcp_config_applied\"}");
|
||||||
}
|
}
|
||||||
} else if (ssid_item && cJSON_IsString(ssid_item)) {
|
}
|
||||||
|
else if (ssid_item && cJSON_IsString(ssid_item))
|
||||||
|
{
|
||||||
cJSON* pass_item = cJSON_GetObjectItem(root, "password");
|
cJSON* pass_item = cJSON_GetObjectItem(root, "password");
|
||||||
if (cJSON_IsString(pass_item)) {
|
if (cJSON_IsString(pass_item))
|
||||||
|
{
|
||||||
nconfig_write(WIFI_SSID, ssid_item->valuestring);
|
nconfig_write(WIFI_SSID, ssid_item->valuestring);
|
||||||
nconfig_write(WIFI_PASSWORD, pass_item->valuestring);
|
nconfig_write(WIFI_PASSWORD, pass_item->valuestring);
|
||||||
nconfig_write(NETIF_TYPE, "dhcp"); // Default to DHCP on new connection
|
nconfig_write(NETIF_TYPE, "dhcp"); // Default to DHCP on new connection
|
||||||
@@ -204,16 +241,22 @@ static esp_err_t setting_post_handler(httpd_req_t *req)
|
|||||||
wifi_disconnect();
|
wifi_disconnect();
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
wifi_connect();
|
wifi_connect();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Password required");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Password required");
|
||||||
}
|
}
|
||||||
} else if (baud_item && cJSON_IsString(baud_item)) {
|
}
|
||||||
|
else if (baud_item && cJSON_IsString(baud_item))
|
||||||
|
{
|
||||||
const char* baudrate = baud_item->valuestring;
|
const char* baudrate = baud_item->valuestring;
|
||||||
ESP_LOGI(TAG, "Received baudrate set request: %s", baudrate);
|
ESP_LOGI(TAG, "Received baudrate set request: %s", baudrate);
|
||||||
nconfig_write(UART_BAUD_RATE, baudrate);
|
nconfig_write(UART_BAUD_RATE, baudrate);
|
||||||
change_baud_rate(strtol(baudrate, NULL, 10));
|
change_baud_rate(strtol(baudrate, NULL, 10));
|
||||||
httpd_resp_sendstr(req, "{\"status\":\"baudrate_updated\"}");
|
httpd_resp_sendstr(req, "{\"status\":\"baudrate_updated\"}");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid payload");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid payload");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
157
main/service/sw.c
Normal file
157
main/service/sw.c
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
//
|
||||||
|
// Created by vl011 on 2025-08-28.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "sw.h"
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <ina3221.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
#include "pca9557.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
|
#define I2C_PORT 0
|
||||||
|
|
||||||
|
#define GPIO_SDA CONFIG_I2C_GPIO_SDA
|
||||||
|
#define GPIO_SCL CONFIG_I2C_GPIO_SCL
|
||||||
|
#define GPIO_MAIN CONFIG_EXPANDER_GPIO_SW_12V
|
||||||
|
#define GPIO_USB CONFIG_EXPANDER_GPIO_SW_5V
|
||||||
|
#define GPIO_PWR CONFIG_EXPANDER_GPIO_TRIGGER_POWER
|
||||||
|
#define GPIO_RST CONFIG_EXPANDER_GPIO_TRIGGER_RESET
|
||||||
|
|
||||||
|
#define POWER_DELAY (CONFIG_TRIGGER_POWER_DELAY_MS * 1000)
|
||||||
|
#define RESET_DELAY (CONFIG_TRIGGER_RESET_DELAY_MS * 1000)
|
||||||
|
|
||||||
|
static const char* TAG = "control";
|
||||||
|
|
||||||
|
static bool load_switch_12v_status = false;
|
||||||
|
static bool load_switch_5v_status = false;
|
||||||
|
|
||||||
|
static SemaphoreHandle_t expander_mutex;
|
||||||
|
#define MUTEX_TIMEOUT (pdMS_TO_TICKS(100))
|
||||||
|
|
||||||
|
static i2c_dev_t pca = {0};
|
||||||
|
|
||||||
|
static esp_timer_handle_t power_trigger_timer;
|
||||||
|
static esp_timer_handle_t reset_trigger_timer;
|
||||||
|
|
||||||
|
static void trigger_off_callback(void* arg)
|
||||||
|
{
|
||||||
|
if (xSemaphoreTake(expander_mutex, MUTEX_TIMEOUT) == pdFALSE)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Control error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t gpio_pin = (int)arg;
|
||||||
|
pca9557_set_level(&pca, gpio_pin, 1);
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_sw()
|
||||||
|
{
|
||||||
|
ESP_ERROR_CHECK(pca9557_init_desc(&pca, 0x18, I2C_PORT, GPIO_SDA, GPIO_SCL));
|
||||||
|
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_MAIN, PCA9557_MODE_OUTPUT));
|
||||||
|
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_USB, PCA9557_MODE_OUTPUT));
|
||||||
|
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_PWR, PCA9557_MODE_OUTPUT));
|
||||||
|
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_RST, PCA9557_MODE_OUTPUT));
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(pca9557_set_level(&pca, GPIO_PWR, 1));
|
||||||
|
ESP_ERROR_CHECK(pca9557_set_level(&pca, GPIO_RST, 1));
|
||||||
|
|
||||||
|
uint32_t val = 0;
|
||||||
|
ESP_ERROR_CHECK(pca9557_get_level(&pca, CONFIG_EXPANDER_GPIO_SW_12V, &val));
|
||||||
|
load_switch_12v_status = val != 0 ? true : false;
|
||||||
|
ESP_ERROR_CHECK(pca9557_get_level(&pca, CONFIG_EXPANDER_GPIO_SW_5V, &val));
|
||||||
|
load_switch_5v_status = val != 0 ? true : false;
|
||||||
|
|
||||||
|
const esp_timer_create_args_t power_timer_args = {
|
||||||
|
.callback = &trigger_off_callback,
|
||||||
|
.arg = (void*)GPIO_PWR,
|
||||||
|
.name = "power_trigger_off"
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_timer_create(&power_timer_args, &power_trigger_timer));
|
||||||
|
|
||||||
|
const esp_timer_create_args_t reset_timer_args = {
|
||||||
|
.callback = &trigger_off_callback,
|
||||||
|
.arg = (void*)GPIO_RST,
|
||||||
|
.name = "power_trigger_off"
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_timer_create(&reset_timer_args, &reset_trigger_timer));
|
||||||
|
|
||||||
|
expander_mutex = xSemaphoreCreateMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void trig_power()
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Trig power");
|
||||||
|
if (xSemaphoreTake(expander_mutex, MUTEX_TIMEOUT) == pdFALSE)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Control error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pca9557_set_level(&pca, GPIO_PWR, 0);
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
esp_timer_stop(power_trigger_timer);
|
||||||
|
esp_timer_start_once(power_trigger_timer, POWER_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void trig_reset()
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Trig reset");
|
||||||
|
if (xSemaphoreTake(expander_mutex, MUTEX_TIMEOUT) == pdFALSE)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Control error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pca9557_set_level(&pca, GPIO_RST, 0);
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
esp_timer_stop(reset_trigger_timer);
|
||||||
|
esp_timer_start_once(reset_trigger_timer, RESET_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_main_load_switch(bool on)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Set main load switch to %s", on ? "on" : "off");
|
||||||
|
if (load_switch_12v_status == on) return;
|
||||||
|
if (xSemaphoreTake(expander_mutex, MUTEX_TIMEOUT) == pdFALSE)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Control error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pca9557_set_level(&pca, GPIO_MAIN, on);
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
load_switch_12v_status = on;
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_usb_load_switch(bool on)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Set usb load switch to %s", on ? "on" : "off");
|
||||||
|
if (load_switch_5v_status == on) return;
|
||||||
|
if (xSemaphoreTake(expander_mutex, MUTEX_TIMEOUT) == pdFALSE)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Control error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pca9557_set_level(&pca, GPIO_USB, on);
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
load_switch_5v_status = on;
|
||||||
|
xSemaphoreGive(expander_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_main_load_switch()
|
||||||
|
{
|
||||||
|
return load_switch_12v_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_usb_load_switch()
|
||||||
|
{
|
||||||
|
return load_switch_5v_status;
|
||||||
|
}
|
||||||
17
main/service/sw.h
Normal file
17
main/service/sw.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by vl011 on 2025-08-28.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ODROID_POWER_MATE_SW_H
|
||||||
|
#define ODROID_POWER_MATE_SW_H
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void init_sw();
|
||||||
|
void trig_power();
|
||||||
|
void trig_reset();
|
||||||
|
void set_main_load_switch(bool on);
|
||||||
|
void set_usb_load_switch(bool on);
|
||||||
|
bool get_main_load_switch();
|
||||||
|
bool get_usb_load_switch();
|
||||||
|
|
||||||
|
#endif //ODROID_POWER_MATE_SW_H
|
||||||
@@ -9,13 +9,13 @@
|
|||||||
#include "nconfig.h"
|
#include "nconfig.h"
|
||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "datalog.h"
|
#include "datalog.h"
|
||||||
|
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
static const char* TAG = "WEBSERVER";
|
static const char* TAG = "WEBSERVER";
|
||||||
|
|
||||||
static esp_err_t index_handler(httpd_req_t *req) {
|
static esp_err_t index_handler(httpd_req_t* req)
|
||||||
|
{
|
||||||
extern const unsigned char index_html_start[] asm("_binary_index_html_gz_start");
|
extern const unsigned char index_html_start[] asm("_binary_index_html_gz_start");
|
||||||
extern const unsigned char index_html_end[] asm("_binary_index_html_gz_end");
|
extern const unsigned char index_html_end[] asm("_binary_index_html_gz_end");
|
||||||
const size_t index_html_size = (index_html_end - index_html_start);
|
const size_t index_html_size = (index_html_end - index_html_start);
|
||||||
@@ -31,7 +31,8 @@ static esp_err_t datalog_download_handler(httpd_req_t *req)
|
|||||||
{
|
{
|
||||||
const char* filepath = datalog_get_path();
|
const char* filepath = datalog_get_path();
|
||||||
FILE* f = fopen(filepath, "r");
|
FILE* f = fopen(filepath, "r");
|
||||||
if (f == NULL) {
|
if (f == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to open datalog file for reading");
|
ESP_LOGE(TAG, "Failed to open datalog file for reading");
|
||||||
httpd_resp_send_404(req);
|
httpd_resp_send_404(req);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -42,8 +43,10 @@ static esp_err_t datalog_download_handler(httpd_req_t *req)
|
|||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
size_t bytes_read;
|
size_t bytes_read;
|
||||||
while ((bytes_read = fread(buffer, 1, sizeof(buffer), f)) > 0) {
|
while ((bytes_read = fread(buffer, 1, sizeof(buffer), f)) > 0)
|
||||||
if (httpd_resp_send_chunk(req, buffer, bytes_read) != ESP_OK) {
|
{
|
||||||
|
if (httpd_resp_send_chunk(req, buffer, bytes_read) != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "File sending failed!");
|
ESP_LOGE(TAG, "File sending failed!");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
httpd_resp_send_chunk(req, NULL, 0);
|
httpd_resp_send_chunk(req, NULL, 0);
|
||||||
@@ -57,14 +60,15 @@ static esp_err_t datalog_download_handler(httpd_req_t *req)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP 서버 시작
|
void start_webserver(void)
|
||||||
void start_webserver(void) {
|
{
|
||||||
httpd_handle_t server = NULL;
|
httpd_handle_t server = NULL;
|
||||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||||
config.stack_size = 1024 * 8;
|
config.stack_size = 1024 * 8;
|
||||||
config.max_uri_handlers = 10;
|
config.max_uri_handlers = 10;
|
||||||
|
|
||||||
if (httpd_start(&server, &config) != ESP_OK) {
|
if (httpd_start(&server, &config) != ESP_OK)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
#define ODROID_REMOTE_HTTP_WEBSERVER_H
|
#define ODROID_REMOTE_HTTP_WEBSERVER_H
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
#include "esp_http_server.h"
|
#include "esp_http_server.h"
|
||||||
#include "system.h"
|
|
||||||
|
|
||||||
void register_wifi_endpoint(httpd_handle_t server);
|
void register_wifi_endpoint(httpd_handle_t server);
|
||||||
void register_ws_endpoint(httpd_handle_t server);
|
void register_ws_endpoint(httpd_handle_t server);
|
||||||
void register_control_endpoint(httpd_handle_t server);
|
void register_control_endpoint(httpd_handle_t server);
|
||||||
void push_data_to_ws(cJSON* data);
|
void push_data_to_ws(cJSON* data);
|
||||||
|
void register_reboot_endpoint(httpd_handle_t server);
|
||||||
esp_err_t change_baud_rate(int baud_rate);
|
esp_err_t change_baud_rate(int baud_rate);
|
||||||
|
|
||||||
#endif //ODROID_REMOTE_HTTP_WEBSERVER_H
|
#endif //ODROID_REMOTE_HTTP_WEBSERVER_H
|
||||||
@@ -23,7 +23,8 @@ static int client_fd = -1;
|
|||||||
static SemaphoreHandle_t client_fd_mutex;
|
static SemaphoreHandle_t client_fd_mutex;
|
||||||
|
|
||||||
// Unified message structure for the websocket queue
|
// Unified message structure for the websocket queue
|
||||||
enum ws_message_type {
|
enum ws_message_type
|
||||||
|
{
|
||||||
WS_MSG_STATUS,
|
WS_MSG_STATUS,
|
||||||
WS_MSG_UART
|
WS_MSG_UART
|
||||||
};
|
};
|
||||||
@@ -31,11 +32,16 @@ enum ws_message_type {
|
|||||||
struct ws_message
|
struct ws_message
|
||||||
{
|
{
|
||||||
enum ws_message_type type;
|
enum ws_message_type type;
|
||||||
union {
|
|
||||||
struct {
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
cJSON* data;
|
cJSON* data;
|
||||||
} status;
|
} status;
|
||||||
struct {
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
size_t len;
|
size_t len;
|
||||||
} uart;
|
} uart;
|
||||||
@@ -51,17 +57,23 @@ static void unified_ws_sender_task(void *arg)
|
|||||||
struct ws_message msg;
|
struct ws_message msg;
|
||||||
const TickType_t PING_INTERVAL = pdMS_TO_TICKS(5000);
|
const TickType_t PING_INTERVAL = pdMS_TO_TICKS(5000);
|
||||||
|
|
||||||
while (1) {
|
while (1)
|
||||||
if (xQueueReceive(ws_queue, &msg, PING_INTERVAL)) {
|
{
|
||||||
|
if (xQueueReceive(ws_queue, &msg, PING_INTERVAL))
|
||||||
|
{
|
||||||
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
||||||
int fd = client_fd;
|
int fd = client_fd;
|
||||||
|
|
||||||
if (fd <= 0) {
|
if (fd <= 0)
|
||||||
|
{
|
||||||
xSemaphoreGive(client_fd_mutex);
|
xSemaphoreGive(client_fd_mutex);
|
||||||
// Free memory if client is not connected
|
// Free memory if client is not connected
|
||||||
if (msg.type == WS_MSG_STATUS) {
|
if (msg.type == WS_MSG_STATUS)
|
||||||
|
{
|
||||||
cJSON_Delete(msg.content.status.data);
|
cJSON_Delete(msg.content.status.data);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
free(msg.content.uart.data);
|
free(msg.content.uart.data);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -70,7 +82,8 @@ static void unified_ws_sender_task(void *arg)
|
|||||||
httpd_ws_frame_t ws_pkt = {0};
|
httpd_ws_frame_t ws_pkt = {0};
|
||||||
esp_err_t err = ESP_FAIL;
|
esp_err_t err = ESP_FAIL;
|
||||||
|
|
||||||
if (msg.type == WS_MSG_STATUS) {
|
if (msg.type == WS_MSG_STATUS)
|
||||||
|
{
|
||||||
char* json_string = cJSON_Print(msg.content.status.data);
|
char* json_string = cJSON_Print(msg.content.status.data);
|
||||||
cJSON_Delete(msg.content.status.data);
|
cJSON_Delete(msg.content.status.data);
|
||||||
|
|
||||||
@@ -79,8 +92,10 @@ static void unified_ws_sender_task(void *arg)
|
|||||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||||
err = httpd_ws_send_frame_async(server, fd, &ws_pkt);
|
err = httpd_ws_send_frame_async(server, fd, &ws_pkt);
|
||||||
free(json_string);
|
free(json_string);
|
||||||
|
}
|
||||||
} else { // WS_MSG_UART
|
else
|
||||||
|
{
|
||||||
|
// WS_MSG_UART
|
||||||
ws_pkt.payload = msg.content.uart.data;
|
ws_pkt.payload = msg.content.uart.data;
|
||||||
ws_pkt.len = msg.content.uart.len;
|
ws_pkt.len = msg.content.uart.len;
|
||||||
ws_pkt.type = HTTPD_WS_TYPE_BINARY;
|
ws_pkt.type = HTTPD_WS_TYPE_BINARY;
|
||||||
@@ -88,24 +103,30 @@ static void unified_ws_sender_task(void *arg)
|
|||||||
free(msg.content.uart.data);
|
free(msg.content.uart.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
ESP_LOGW(TAG, "unified_ws_sender_task: async send failed for fd %d, error: %s", fd, esp_err_to_name(err));
|
{
|
||||||
|
ESP_LOGW(TAG, "unified_ws_sender_task: async send failed for fd %d, error: %s", fd,
|
||||||
|
esp_err_to_name(err));
|
||||||
client_fd = -1;
|
client_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
xSemaphoreGive(client_fd_mutex);
|
xSemaphoreGive(client_fd_mutex);
|
||||||
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
// Queue receive timed out, send a PING to keep connection alive
|
// Queue receive timed out, send a PING to keep connection alive
|
||||||
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
||||||
int fd = client_fd;
|
int fd = client_fd;
|
||||||
if (fd > 0) {
|
if (fd > 0)
|
||||||
|
{
|
||||||
httpd_ws_frame_t ping_pkt = {0};
|
httpd_ws_frame_t ping_pkt = {0};
|
||||||
ping_pkt.type = HTTPD_WS_TYPE_PING;
|
ping_pkt.type = HTTPD_WS_TYPE_PING;
|
||||||
ping_pkt.final = true;
|
ping_pkt.final = true;
|
||||||
esp_err_t err = httpd_ws_send_frame_async(server, fd, &ping_pkt);
|
esp_err_t err = httpd_ws_send_frame_async(server, fd, &ping_pkt);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
ESP_LOGW(TAG, "Failed to send PING frame, closing connection for fd %d, error: %s", fd, esp_err_to_name(err));
|
{
|
||||||
|
ESP_LOGW(TAG, "Failed to send PING frame, closing connection for fd %d, error: %s", fd,
|
||||||
|
esp_err_to_name(err));
|
||||||
client_fd = -1;
|
client_fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,10 +148,12 @@ static void uart_polling_task(void *arg)
|
|||||||
TickType_t last_client_check = 0;
|
TickType_t last_client_check = 0;
|
||||||
const TickType_t CLIENT_CHECK_INTERVAL = pdMS_TO_TICKS(100);
|
const TickType_t CLIENT_CHECK_INTERVAL = pdMS_TO_TICKS(100);
|
||||||
|
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
TickType_t current_time = xTaskGetTickCount();
|
TickType_t current_time = xTaskGetTickCount();
|
||||||
|
|
||||||
if (current_time - last_client_check >= CLIENT_CHECK_INTERVAL) {
|
if (current_time - last_client_check >= CLIENT_CHECK_INTERVAL)
|
||||||
|
{
|
||||||
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
||||||
cached_client_fd = client_fd;
|
cached_client_fd = client_fd;
|
||||||
xSemaphoreGive(client_fd_mutex);
|
xSemaphoreGive(client_fd_mutex);
|
||||||
@@ -140,15 +163,20 @@ static void uart_polling_task(void *arg)
|
|||||||
size_t available_len;
|
size_t available_len;
|
||||||
esp_err_t err = uart_get_buffered_data_len(UART_NUM, &available_len);
|
esp_err_t err = uart_get_buffered_data_len(UART_NUM, &available_len);
|
||||||
|
|
||||||
if (err != ESP_OK || available_len == 0) {
|
if (err != ESP_OK || available_len == 0)
|
||||||
|
{
|
||||||
consecutive_empty_polls++;
|
consecutive_empty_polls++;
|
||||||
if (consecutive_empty_polls > 5) {
|
if (consecutive_empty_polls > 5)
|
||||||
|
{
|
||||||
current_interval = MAX_POLLING_INTERVAL;
|
current_interval = MAX_POLLING_INTERVAL;
|
||||||
} else if (consecutive_empty_polls > 2) {
|
}
|
||||||
|
else if (consecutive_empty_polls > 2)
|
||||||
|
{
|
||||||
current_interval = pdMS_TO_TICKS(5);
|
current_interval = pdMS_TO_TICKS(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cached_client_fd <= 0) {
|
if (cached_client_fd <= 0)
|
||||||
|
{
|
||||||
vTaskDelay(pdMS_TO_TICKS(50));
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -160,20 +188,24 @@ static void uart_polling_task(void *arg)
|
|||||||
consecutive_empty_polls = 0;
|
consecutive_empty_polls = 0;
|
||||||
current_interval = MIN_POLLING_INTERVAL;
|
current_interval = MIN_POLLING_INTERVAL;
|
||||||
|
|
||||||
if (cached_client_fd <= 0) {
|
if (cached_client_fd <= 0)
|
||||||
|
{
|
||||||
uart_flush_input(UART_NUM);
|
uart_flush_input(UART_NUM);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t total_processed = 0;
|
size_t total_processed = 0;
|
||||||
while (available_len > 0 && total_processed < BUF_SIZE) {
|
while (available_len > 0 && total_processed < BUF_SIZE)
|
||||||
size_t read_size = (available_len > (BUF_SIZE - total_processed)) ?
|
{
|
||||||
(BUF_SIZE - total_processed) : available_len;
|
size_t read_size = (available_len > (BUF_SIZE - total_processed))
|
||||||
|
? (BUF_SIZE - total_processed)
|
||||||
|
: available_len;
|
||||||
|
|
||||||
int bytes_read = uart_read_bytes(UART_NUM, data_buf + total_processed,
|
int bytes_read = uart_read_bytes(UART_NUM, data_buf + total_processed,
|
||||||
read_size, READ_TIMEOUT);
|
read_size, READ_TIMEOUT);
|
||||||
|
|
||||||
if (bytes_read <= 0) {
|
if (bytes_read <= 0)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,17 +215,21 @@ static void uart_polling_task(void *arg)
|
|||||||
uart_get_buffered_data_len(UART_NUM, &available_len);
|
uart_get_buffered_data_len(UART_NUM, &available_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_processed > 0) {
|
if (total_processed > 0)
|
||||||
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
while (offset < total_processed) {
|
while (offset < total_processed)
|
||||||
const size_t chunk_size = (total_processed - offset > CHUNK_SIZE) ?
|
{
|
||||||
CHUNK_SIZE : (total_processed - offset);
|
const size_t chunk_size = (total_processed - offset > CHUNK_SIZE)
|
||||||
|
? CHUNK_SIZE
|
||||||
|
: (total_processed - offset);
|
||||||
|
|
||||||
struct ws_message msg;
|
struct ws_message msg;
|
||||||
msg.type = WS_MSG_UART;
|
msg.type = WS_MSG_UART;
|
||||||
msg.content.uart.data = malloc(chunk_size);
|
msg.content.uart.data = malloc(chunk_size);
|
||||||
if (!msg.content.uart.data) {
|
if (!msg.content.uart.data)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to allocate memory for uart ws msg");
|
ESP_LOGE(TAG, "Failed to allocate memory for uart ws msg");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -201,8 +237,10 @@ static void uart_polling_task(void *arg)
|
|||||||
memcpy(msg.content.uart.data, data_buf + offset, chunk_size);
|
memcpy(msg.content.uart.data, data_buf + offset, chunk_size);
|
||||||
msg.content.uart.len = chunk_size;
|
msg.content.uart.len = chunk_size;
|
||||||
|
|
||||||
if (xQueueSend(ws_queue, &msg, 0) != pdPASS) {
|
if (xQueueSend(ws_queue, &msg, 0) != pdPASS)
|
||||||
if (xQueueSend(ws_queue, &msg, pdMS_TO_TICKS(5)) != pdPASS) {
|
{
|
||||||
|
if (xQueueSend(ws_queue, &msg, pdMS_TO_TICKS(5)) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "ws sender queue full, dropping %zu bytes", chunk_size);
|
ESP_LOGW(TAG, "ws sender queue full, dropping %zu bytes", chunk_size);
|
||||||
free(msg.content.uart.data);
|
free(msg.content.uart.data);
|
||||||
}
|
}
|
||||||
@@ -212,9 +250,12 @@ static void uart_polling_task(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (available_len > 0) {
|
if (available_len > 0)
|
||||||
|
{
|
||||||
vTaskDelay(MIN_POLLING_INTERVAL);
|
vTaskDelay(MIN_POLLING_INTERVAL);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
vTaskDelay(current_interval);
|
vTaskDelay(current_interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,10 +263,13 @@ static void uart_polling_task(void *arg)
|
|||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t ws_handler(httpd_req_t *req) {
|
static esp_err_t ws_handler(httpd_req_t* req)
|
||||||
if (req->method == HTTP_GET) {
|
{
|
||||||
|
if (req->method == HTTP_GET)
|
||||||
|
{
|
||||||
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
||||||
if (client_fd > 0) {
|
if (client_fd > 0)
|
||||||
|
{
|
||||||
// A client is already connected. Reject the new connection.
|
// A client is already connected. Reject the new connection.
|
||||||
ESP_LOGW(TAG, "Another client tried to connect, but a session is already active. Rejecting.");
|
ESP_LOGW(TAG, "Another client tried to connect, but a session is already active. Rejecting.");
|
||||||
xSemaphoreGive(client_fd_mutex);
|
xSemaphoreGive(client_fd_mutex);
|
||||||
@@ -251,10 +295,12 @@ static esp_err_t ws_handler(httpd_req_t *req) {
|
|||||||
ws_pkt.type = HTTPD_WS_TYPE_BINARY;
|
ws_pkt.type = HTTPD_WS_TYPE_BINARY;
|
||||||
|
|
||||||
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, BUF_SIZE);
|
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, BUF_SIZE);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "httpd_ws_recv_frame failed with error: %s", esp_err_to_name(ret));
|
ESP_LOGW(TAG, "httpd_ws_recv_frame failed with error: %s", esp_err_to_name(ret));
|
||||||
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
xSemaphoreTake(client_fd_mutex, portMAX_DELAY);
|
||||||
if (httpd_req_to_sockfd(req) == client_fd) {
|
if (httpd_req_to_sockfd(req) == client_fd)
|
||||||
|
{
|
||||||
client_fd = -1;
|
client_fd = -1;
|
||||||
}
|
}
|
||||||
xSemaphoreGive(client_fd_mutex);
|
xSemaphoreGive(client_fd_mutex);
|
||||||
|
|||||||
@@ -4,43 +4,83 @@
|
|||||||
|
|
||||||
#include <system.h>
|
#include <system.h>
|
||||||
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
|
#include <esp_timer.h>
|
||||||
|
#include "esp_http_server.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static const char* TAG = "odroid";
|
static const char* TAG = "odroid";
|
||||||
int t = 0;
|
|
||||||
|
|
||||||
TaskHandle_t reboot_handle = NULL;
|
static esp_timer_handle_t reboot_timer_handle = NULL;
|
||||||
|
|
||||||
static void reboot_task(void *arg)
|
static void reboot_timer_callback(void* arg)
|
||||||
{
|
{
|
||||||
while (t > 0)
|
ESP_LOGI(TAG, "Rebooting now...");
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "ESP will reboot in [%d] sec..., If you want stop reboot, use command \"reboot -s\"", t);
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
||||||
--t;
|
|
||||||
}
|
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_reboot_timer(int sec)
|
void start_reboot_timer(int sec)
|
||||||
{
|
{
|
||||||
|
if (reboot_timer_handle != NULL)
|
||||||
if (reboot_handle != NULL)
|
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "The reboot timer is already running.");
|
ESP_LOGW(TAG, "The reboot timer is already running.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t = sec;
|
|
||||||
xTaskCreate(reboot_task, "reboot_task", 2048, NULL, 8, &reboot_handle);
|
ESP_LOGI(TAG, "Device will reboot in %d seconds.", sec);
|
||||||
|
|
||||||
|
const esp_timer_create_args_t reboot_timer_args = {
|
||||||
|
.callback = &reboot_timer_callback,
|
||||||
|
.name = "reboot-timer"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (esp_timer_create(&reboot_timer_args, &reboot_timer_handle) != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "Failed to create reboot timer.");
|
||||||
|
reboot_timer_handle = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esp_timer_start_once(reboot_timer_handle, (uint64_t)sec * 1000000) != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "Failed to start reboot timer.");
|
||||||
|
esp_timer_delete(reboot_timer_handle);
|
||||||
|
reboot_timer_handle = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t reboot_post_handler(httpd_req_t* req)
|
||||||
|
{
|
||||||
|
httpd_resp_set_type(req, "application/json");
|
||||||
|
const char* resp_str = "{\"status\": \"reboot timer started\"}";
|
||||||
|
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||||
|
|
||||||
|
start_reboot_timer(3);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop_reboot_timer()
|
void stop_reboot_timer()
|
||||||
{
|
{
|
||||||
if (reboot_handle == NULL)
|
if (reboot_timer_handle == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vTaskDelete(reboot_handle);
|
esp_timer_stop(reboot_timer_handle);
|
||||||
|
esp_timer_delete(reboot_timer_handle);
|
||||||
|
reboot_timer_handle = NULL;
|
||||||
|
ESP_LOGI(TAG, "Reboot timer stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_reboot_endpoint(httpd_handle_t server)
|
||||||
|
{
|
||||||
|
httpd_uri_t post_uri = {
|
||||||
|
.uri = "/api/reboot",
|
||||||
|
.method = HTTP_POST,
|
||||||
|
.handler = reboot_post_handler,
|
||||||
|
.user_ctx = NULL
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &post_uri);
|
||||||
}
|
}
|
||||||
184
main/wifi/wifi.c
184
main/wifi/wifi.c
@@ -69,8 +69,10 @@ const char* auth_mode_str(wifi_auth_mode_t mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* wifi_reason_str(wifi_err_reason_t reason) {
|
static const char* wifi_reason_str(wifi_err_reason_t reason)
|
||||||
switch (reason) {
|
{
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
case WIFI_REASON_UNSPECIFIED: return "UNSPECIFIED";
|
case WIFI_REASON_UNSPECIFIED: return "UNSPECIFIED";
|
||||||
case WIFI_REASON_AUTH_EXPIRE: return "AUTH_EXPIRE";
|
case WIFI_REASON_AUTH_EXPIRE: return "AUTH_EXPIRE";
|
||||||
case WIFI_REASON_AUTH_LEAVE: return "AUTH_LEAVE";
|
case WIFI_REASON_AUTH_LEAVE: return "AUTH_LEAVE";
|
||||||
@@ -129,7 +131,8 @@ static void handler_on_wifi_disconnect(void *arg, esp_event_base_t event_base,
|
|||||||
int32_t event_id, void* event_data)
|
int32_t event_id, void* event_data)
|
||||||
{
|
{
|
||||||
s_retry_num++;
|
s_retry_num++;
|
||||||
if (s_retry_num > MAX_RETRY) {
|
if (s_retry_num > MAX_RETRY)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "WiFi Connect failed %d times, stop reconnect.", s_retry_num);
|
ESP_LOGW(TAG, "WiFi Connect failed %d times, stop reconnect.", s_retry_num);
|
||||||
/* let example_wifi_sta_do_connect() return */
|
/* let example_wifi_sta_do_connect() return */
|
||||||
|
|
||||||
@@ -138,14 +141,16 @@ static void handler_on_wifi_disconnect(void *arg, esp_event_base_t event_base,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wifi_event_sta_disconnected_t* disconn = event_data;
|
wifi_event_sta_disconnected_t* disconn = event_data;
|
||||||
if (disconn->reason == WIFI_REASON_ROAMING) {
|
if (disconn->reason == WIFI_REASON_ROAMING)
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "station roaming, do nothing");
|
ESP_LOGD(TAG, "station roaming, do nothing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_LOGW(TAG, "Wi-Fi disconnected, reason: (%s)", wifi_reason_str(disconn->reason));
|
ESP_LOGW(TAG, "Wi-Fi disconnected, reason: (%s)", wifi_reason_str(disconn->reason));
|
||||||
ESP_LOGI(TAG, "Trying to reconnect...");
|
ESP_LOGI(TAG, "Trying to reconnect...");
|
||||||
esp_err_t err = esp_wifi_connect();
|
esp_err_t err = esp_wifi_connect();
|
||||||
if (err == ESP_ERR_WIFI_NOT_STARTED) {
|
if (err == ESP_ERR_WIFI_NOT_STARTED)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(err);
|
ESP_ERROR_CHECK(err);
|
||||||
@@ -154,7 +159,6 @@ static void handler_on_wifi_disconnect(void *arg, esp_event_base_t event_base,
|
|||||||
static void handler_on_wifi_connect(void* esp_netif, esp_event_base_t event_base,
|
static void handler_on_wifi_connect(void* esp_netif, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data)
|
int32_t event_id, void* event_data)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handler_on_sta_got_ip(void* arg, esp_event_base_t event_base,
|
static void handler_on_sta_got_ip(void* arg, esp_event_base_t event_base,
|
||||||
@@ -163,10 +167,12 @@ static void handler_on_sta_got_ip(void *arg, esp_event_base_t event_base,
|
|||||||
stop_reboot_timer();
|
stop_reboot_timer();
|
||||||
s_retry_num = 0;
|
s_retry_num = 0;
|
||||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
|
||||||
if (strcmp("sta", esp_netif_get_desc(event->esp_netif)) != 0) {
|
if (strcmp("sta", esp_netif_get_desc(event->esp_netif)) != 0)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));
|
ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif),
|
||||||
|
IP2STR(&event->ip_info.ip));
|
||||||
ESP_LOGI(TAG, "- IPv4 address: " IPSTR ",", IP2STR(&event->ip_info.ip));
|
ESP_LOGI(TAG, "- IPv4 address: " IPSTR ",", IP2STR(&event->ip_info.ip));
|
||||||
sync_time();
|
sync_time();
|
||||||
led_set(LED_BLU, BLINK_SOLID);
|
led_set(LED_BLU, BLINK_SOLID);
|
||||||
@@ -175,11 +181,14 @@ static void handler_on_sta_got_ip(void *arg, esp_event_base_t event_base,
|
|||||||
static void wifi_ap_event_handler(void* arg, esp_event_base_t event_base,
|
static void wifi_ap_event_handler(void* arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data)
|
int32_t event_id, void* event_data)
|
||||||
{
|
{
|
||||||
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
|
if (event_id == WIFI_EVENT_AP_STACONNECTED)
|
||||||
|
{
|
||||||
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*)event_data;
|
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*)event_data;
|
||||||
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
|
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
|
||||||
MAC2STR(event->mac), event->aid);
|
MAC2STR(event->mac), event->aid);
|
||||||
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
}
|
||||||
|
else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
|
||||||
|
{
|
||||||
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*)event_data;
|
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*)event_data;
|
||||||
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
|
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
|
||||||
MAC2STR(event->mac), event->aid);
|
MAC2STR(event->mac), event->aid);
|
||||||
@@ -201,11 +210,13 @@ static void wifi_start(wifi_mode_t mode)
|
|||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||||
|
|
||||||
if (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) {
|
if (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA)
|
||||||
|
{
|
||||||
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA();
|
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA();
|
||||||
wifi_sta_netif = esp_netif_create_wifi(WIFI_IF_STA, &esp_netif_config);
|
wifi_sta_netif = esp_netif_create_wifi(WIFI_IF_STA, &esp_netif_config);
|
||||||
|
|
||||||
if (nconfig_read(NETIF_TYPE, type_buf, sizeof(type_buf)) == ESP_OK && strcmp(type_buf, "static") == 0) {
|
if (nconfig_read(NETIF_TYPE, type_buf, sizeof(type_buf)) == ESP_OK && strcmp(type_buf, "static") == 0)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Using static IP configuration");
|
ESP_LOGI(TAG, "Using static IP configuration");
|
||||||
char ip_buf[16], gw_buf[16], mask_buf[16], dns1_buf[16], dns2_buf[16];
|
char ip_buf[16], gw_buf[16], mask_buf[16], dns1_buf[16], dns2_buf[16];
|
||||||
nconfig_read(NETIF_IP, ip_buf, sizeof(ip_buf));
|
nconfig_read(NETIF_IP, ip_buf, sizeof(ip_buf));
|
||||||
@@ -217,7 +228,9 @@ static void wifi_start(wifi_mode_t mode)
|
|||||||
wifi_use_static(ip_buf, gw_buf, mask_buf, "8.8.8.8", "8.8.4.4");
|
wifi_use_static(ip_buf, gw_buf, mask_buf, "8.8.8.8", "8.8.4.4");
|
||||||
else
|
else
|
||||||
wifi_use_static(ip_buf, gw_buf, mask_buf, dns1, dns2);
|
wifi_use_static(ip_buf, gw_buf, mask_buf, dns1, dns2);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Using DHCP configuration");
|
ESP_LOGI(TAG, "Using DHCP configuration");
|
||||||
wifi_use_dhcp();
|
wifi_use_dhcp();
|
||||||
}
|
}
|
||||||
@@ -228,11 +241,14 @@ static void wifi_start(wifi_mode_t mode)
|
|||||||
set_hostname(wifi_sta_netif, buf);
|
set_hostname(wifi_sta_netif, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA) {
|
if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA)
|
||||||
|
{
|
||||||
esp_netif_inherent_config_t esp_netif_config_ap = ESP_NETIF_INHERENT_DEFAULT_WIFI_AP();
|
esp_netif_inherent_config_t esp_netif_config_ap = ESP_NETIF_INHERENT_DEFAULT_WIFI_AP();
|
||||||
wifi_ap_netif = esp_netif_create_wifi(WIFI_IF_AP, &esp_netif_config_ap);
|
wifi_ap_netif = esp_netif_create_wifi(WIFI_IF_AP, &esp_netif_config_ap);
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &wifi_ap_event_handler, NULL));
|
ESP_ERROR_CHECK(
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &wifi_ap_event_handler, NULL));
|
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &wifi_ap_event_handler, NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &wifi_ap_event_handler,
|
||||||
|
NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_wifi_set_default_wifi_sta_handlers();
|
esp_wifi_set_default_wifi_sta_handlers();
|
||||||
@@ -246,23 +262,27 @@ static void wifi_start(wifi_mode_t mode)
|
|||||||
static void wifi_stop(void)
|
static void wifi_stop(void)
|
||||||
{
|
{
|
||||||
esp_err_t err = esp_wifi_stop();
|
esp_err_t err = esp_wifi_stop();
|
||||||
if (err == ESP_ERR_WIFI_NOT_INIT) {
|
if (err == ESP_ERR_WIFI_NOT_INIT)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(err);
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
if (wifi_ap_netif) {
|
if (wifi_ap_netif)
|
||||||
|
{
|
||||||
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &wifi_ap_event_handler);
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &wifi_ap_event_handler);
|
||||||
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &wifi_ap_event_handler);
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &wifi_ap_event_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_deinit());
|
ESP_ERROR_CHECK(esp_wifi_deinit());
|
||||||
|
|
||||||
if (wifi_sta_netif) {
|
if (wifi_sta_netif)
|
||||||
|
{
|
||||||
esp_netif_destroy(wifi_sta_netif);
|
esp_netif_destroy(wifi_sta_netif);
|
||||||
wifi_sta_netif = NULL;
|
wifi_sta_netif = NULL;
|
||||||
}
|
}
|
||||||
if (wifi_ap_netif) {
|
if (wifi_ap_netif)
|
||||||
|
{
|
||||||
esp_netif_destroy(wifi_ap_netif);
|
esp_netif_destroy(wifi_ap_netif);
|
||||||
wifi_ap_netif = NULL;
|
wifi_ap_netif = NULL;
|
||||||
}
|
}
|
||||||
@@ -273,15 +293,18 @@ static esp_err_t wifi_sta_do_connect(wifi_config_t wifi_config)
|
|||||||
{
|
{
|
||||||
stop_reboot_timer();
|
stop_reboot_timer();
|
||||||
s_retry_num = 0;
|
s_retry_num = 0;
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, handler_on_wifi_disconnect, NULL));
|
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, handler_on_wifi_disconnect,
|
||||||
|
NULL));
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_on_sta_got_ip, NULL));
|
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_on_sta_got_ip, NULL));
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, handler_on_wifi_connect, wifi_sta_netif));
|
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, handler_on_wifi_connect,
|
||||||
|
wifi_sta_netif));
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Connecting to %s...", (char*)wifi_config.sta.ssid);
|
ESP_LOGI(TAG, "Connecting to %s...", (char*)wifi_config.sta.ssid);
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||||
esp_err_t ret = esp_wifi_connect();
|
esp_err_t ret = esp_wifi_connect();
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "WiFi connect failed! ret:%x", ret);
|
ESP_LOGE(TAG, "WiFi connect failed! ret:%x", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -310,48 +333,65 @@ static esp_err_t do_connect(void)
|
|||||||
char mode_buf[16] = {0};
|
char mode_buf[16] = {0};
|
||||||
wifi_mode_t mode = WIFI_MODE_STA; // Default mode
|
wifi_mode_t mode = WIFI_MODE_STA; // Default mode
|
||||||
|
|
||||||
if (nconfig_read(WIFI_MODE, mode_buf, sizeof(mode_buf)) == ESP_OK) {
|
if (nconfig_read(WIFI_MODE, mode_buf, sizeof(mode_buf)) == ESP_OK)
|
||||||
if (strcmp(mode_buf, "apsta") == 0) {
|
{
|
||||||
|
if (strcmp(mode_buf, "apsta") == 0)
|
||||||
|
{
|
||||||
mode = WIFI_MODE_APSTA;
|
mode = WIFI_MODE_APSTA;
|
||||||
ESP_LOGI(TAG, "Starting in APSTA mode");
|
ESP_LOGI(TAG, "Starting in APSTA mode");
|
||||||
} else { // "sta" or anything else defaults to STA
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// "sta" or anything else defaults to STA
|
||||||
mode = WIFI_MODE_STA;
|
mode = WIFI_MODE_STA;
|
||||||
ESP_LOGI(TAG, "Starting in STA mode");
|
ESP_LOGI(TAG, "Starting in STA mode");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "WIFI_MODE not set, defaulting to STA mode");
|
ESP_LOGI(TAG, "WIFI_MODE not set, defaulting to STA mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_start(mode);
|
wifi_start(mode);
|
||||||
|
|
||||||
// Configure and connect STA interface if needed
|
// Configure and connect STA interface if needed
|
||||||
if (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) {
|
if (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA)
|
||||||
|
{
|
||||||
wifi_config_t sta_config = {0};
|
wifi_config_t sta_config = {0};
|
||||||
bool sta_creds_ok = false;
|
bool sta_creds_ok = false;
|
||||||
if (nconfig_read(WIFI_SSID, (char*)sta_config.sta.ssid, 32) == ESP_OK && strlen((char*)sta_config.sta.ssid) > 0) {
|
if (nconfig_read(WIFI_SSID, (char*)sta_config.sta.ssid, 32) == ESP_OK && strlen((char*)sta_config.sta.ssid) > 0)
|
||||||
if (nconfig_read(WIFI_PASSWORD, (char*)sta_config.sta.password, 64) == ESP_OK) {
|
{
|
||||||
|
if (nconfig_read(WIFI_PASSWORD, (char*)sta_config.sta.password, 64) == ESP_OK)
|
||||||
|
{
|
||||||
sta_creds_ok = true;
|
sta_creds_ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sta_creds_ok) {
|
if (sta_creds_ok)
|
||||||
|
{
|
||||||
err = wifi_sta_do_connect(sta_config);
|
err = wifi_sta_do_connect(sta_config);
|
||||||
if (err != ESP_OK && mode == WIFI_MODE_STA) {
|
if (err != ESP_OK && mode == WIFI_MODE_STA)
|
||||||
|
{
|
||||||
// In STA-only mode, failure to connect is a fatal error
|
// In STA-only mode, failure to connect is a fatal error
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if (mode == WIFI_MODE_STA) {
|
}
|
||||||
|
else if (mode == WIFI_MODE_STA)
|
||||||
|
{
|
||||||
// In STA-only mode, missing credentials is a fatal error
|
// In STA-only mode, missing credentials is a fatal error
|
||||||
ESP_LOGE(TAG, "Missing STA credentials in STA mode.");
|
ESP_LOGE(TAG, "Missing STA credentials in STA mode.");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// In APSTA mode, missing credentials is a warning
|
// In APSTA mode, missing credentials is a warning
|
||||||
ESP_LOGW(TAG, "Missing STA credentials in APSTA mode. STA will not connect.");
|
ESP_LOGW(TAG, "Missing STA credentials in APSTA mode. STA will not connect.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure AP interface if needed
|
// Configure AP interface if needed
|
||||||
if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA) {
|
if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA)
|
||||||
|
{
|
||||||
char ap_ssid[32], ap_pass[64];
|
char ap_ssid[32], ap_pass[64];
|
||||||
wifi_config_t ap_config = {
|
wifi_config_t ap_config = {
|
||||||
.ap = {
|
.ap = {
|
||||||
@@ -362,15 +402,21 @@ static esp_err_t do_connect(void)
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (nconfig_read(AP_SSID, ap_ssid, sizeof(ap_ssid)) == ESP_OK && strlen(ap_ssid) > 0) {
|
if (nconfig_read(AP_SSID, ap_ssid, sizeof(ap_ssid)) == ESP_OK && strlen(ap_ssid) > 0)
|
||||||
|
{
|
||||||
strcpy((char*)ap_config.ap.ssid, ap_ssid);
|
strcpy((char*)ap_config.ap.ssid, ap_ssid);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
strcpy((char*)ap_config.ap.ssid, "ODROID-REMOTE-AP");
|
strcpy((char*)ap_config.ap.ssid, "ODROID-REMOTE-AP");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nconfig_read(AP_PASSWORD, ap_pass, sizeof(ap_pass)) == ESP_OK && strlen(ap_pass) >= 8) {
|
if (nconfig_read(AP_PASSWORD, ap_pass, sizeof(ap_pass)) == ESP_OK && strlen(ap_pass) >= 8)
|
||||||
|
{
|
||||||
strcpy((char*)ap_config.ap.password, ap_pass);
|
strcpy((char*)ap_config.ap.password, ap_pass);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ap_config.ap.authmode = WIFI_AUTH_OPEN;
|
ap_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||||
memset(ap_config.ap.password, 0, sizeof(ap_config.ap.password));
|
memset(ap_config.ap.password, 0, sizeof(ap_config.ap.password));
|
||||||
}
|
}
|
||||||
@@ -388,13 +434,16 @@ esp_err_t wifi_connect(void)
|
|||||||
led_set(LED_BLU, BLINK_DOUBLE);
|
led_set(LED_BLU, BLINK_DOUBLE);
|
||||||
|
|
||||||
static esp_sntp_config_t ntp_cfg = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(3,
|
static esp_sntp_config_t ntp_cfg = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(3,
|
||||||
ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org", "216.239.35.0")); // google public ntp
|
ESP_SNTP_SERVER_LIST(
|
||||||
|
"time.windows.com", "pool.ntp.org",
|
||||||
|
"216.239.35.0")); // google public ntp
|
||||||
ntp_cfg.start = false;
|
ntp_cfg.start = false;
|
||||||
ntp_cfg.sync_cb = sntp_sync_time_cb;
|
ntp_cfg.sync_cb = sntp_sync_time_cb;
|
||||||
ntp_cfg.smooth_sync = true; // Sync immediately when started
|
ntp_cfg.smooth_sync = true; // Sync immediately when started
|
||||||
esp_netif_sntp_init(&ntp_cfg);
|
esp_netif_sntp_init(&ntp_cfg);
|
||||||
|
|
||||||
if (do_connect() != ESP_OK) {
|
if (do_connect() != ESP_OK)
|
||||||
|
{
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(esp_register_shutdown_handler(&wifi_shutdown));
|
ESP_ERROR_CHECK(esp_register_shutdown_handler(&wifi_shutdown));
|
||||||
@@ -414,7 +463,8 @@ void wifi_scan_aps(wifi_ap_record_t **ap_records, uint16_t* count)
|
|||||||
ESP_LOGI(TAG, "Starting WiFi scan...");
|
ESP_LOGI(TAG, "Starting WiFi scan...");
|
||||||
|
|
||||||
esp_err_t err = esp_wifi_scan_start(NULL, true);
|
esp_err_t err = esp_wifi_scan_start(NULL, true);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "esp_wifi_scan_start failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "esp_wifi_scan_start failed: %s", esp_err_to_name(err));
|
||||||
*count = 0;
|
*count = 0;
|
||||||
*ap_records = NULL;
|
*ap_records = NULL;
|
||||||
@@ -435,7 +485,8 @@ void wifi_scan_aps(wifi_ap_record_t **ap_records, uint16_t* count)
|
|||||||
esp_err_t wifi_get_current_ap_info(wifi_ap_record_t* ap_info)
|
esp_err_t wifi_get_current_ap_info(wifi_ap_record_t* ap_info)
|
||||||
{
|
{
|
||||||
esp_err_t ret = esp_wifi_sta_get_ap_info(ap_info);
|
esp_err_t ret = esp_wifi_sta_get_ap_info(ap_info);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
// Clear ssid and set invalid rssi on error
|
// Clear ssid and set invalid rssi on error
|
||||||
memset(ap_info->ssid, 0, sizeof(ap_info->ssid));
|
memset(ap_info->ssid, 0, sizeof(ap_info->ssid));
|
||||||
ap_info->rssi = -127;
|
ap_info->rssi = -127;
|
||||||
@@ -450,7 +501,8 @@ esp_err_t wifi_get_current_ip_info(esp_netif_ip_info_t *ip_info)
|
|||||||
|
|
||||||
esp_err_t wifi_get_dns_info(esp_netif_dns_type_t type, esp_netif_dns_info_t* dns_info)
|
esp_err_t wifi_get_dns_info(esp_netif_dns_type_t type, esp_netif_dns_info_t* dns_info)
|
||||||
{
|
{
|
||||||
if (wifi_sta_netif) {
|
if (wifi_sta_netif)
|
||||||
|
{
|
||||||
return esp_netif_get_dns_info(wifi_sta_netif, type, dns_info);
|
return esp_netif_get_dns_info(wifi_sta_netif, type, dns_info);
|
||||||
}
|
}
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -458,12 +510,14 @@ esp_err_t wifi_get_dns_info(esp_netif_dns_type_t type, esp_netif_dns_info_t *dns
|
|||||||
|
|
||||||
esp_err_t wifi_use_static(const char* ip, const char* gw, const char* netmask, const char* dns1, const char* dns2)
|
esp_err_t wifi_use_static(const char* ip, const char* gw, const char* netmask, const char* dns1, const char* dns2)
|
||||||
{
|
{
|
||||||
if (wifi_sta_netif == NULL) {
|
if (wifi_sta_netif == NULL)
|
||||||
|
{
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = esp_netif_dhcpc_stop(wifi_sta_netif);
|
esp_err_t err = esp_netif_dhcpc_stop(wifi_sta_netif);
|
||||||
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
|
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to stop DHCP client: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to stop DHCP client: %s", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -473,23 +527,30 @@ esp_err_t wifi_use_static(const char *ip, const char *gw, const char *netmask, c
|
|||||||
inet_pton(AF_INET, gw, &ip_info.gw);
|
inet_pton(AF_INET, gw, &ip_info.gw);
|
||||||
inet_pton(AF_INET, netmask, &ip_info.netmask);
|
inet_pton(AF_INET, netmask, &ip_info.netmask);
|
||||||
err = esp_netif_set_ip_info(wifi_sta_netif, &ip_info);
|
err = esp_netif_set_ip_info(wifi_sta_netif, &ip_info);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to set static IP info: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to set static IP info: %s", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_netif_dns_info_t dns_info;
|
esp_netif_dns_info_t dns_info;
|
||||||
if (dns1 && strlen(dns1) > 0) {
|
if (dns1 && strlen(dns1) > 0)
|
||||||
|
{
|
||||||
inet_pton(AF_INET, dns1, &dns_info.ip.u_addr.ip4);
|
inet_pton(AF_INET, dns1, &dns_info.ip.u_addr.ip4);
|
||||||
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_MAIN, &dns_info);
|
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_MAIN, &dns_info);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_MAIN, NULL);
|
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_MAIN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dns2 && strlen(dns2) > 0) {
|
if (dns2 && strlen(dns2) > 0)
|
||||||
|
{
|
||||||
inet_pton(AF_INET, dns2, &dns_info.ip.u_addr.ip4);
|
inet_pton(AF_INET, dns2, &dns_info.ip.u_addr.ip4);
|
||||||
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_BACKUP, &dns_info);
|
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_BACKUP, &dns_info);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_BACKUP, NULL);
|
esp_netif_set_dns_info(wifi_sta_netif, ESP_NETIF_DNS_BACKUP, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,11 +559,13 @@ esp_err_t wifi_use_static(const char *ip, const char *gw, const char *netmask, c
|
|||||||
|
|
||||||
esp_err_t wifi_use_dhcp(void)
|
esp_err_t wifi_use_dhcp(void)
|
||||||
{
|
{
|
||||||
if (wifi_sta_netif == NULL) {
|
if (wifi_sta_netif == NULL)
|
||||||
|
{
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
esp_err_t err = esp_netif_dhcpc_start(wifi_sta_netif);
|
esp_err_t err = esp_netif_dhcpc_start(wifi_sta_netif);
|
||||||
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) {
|
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to start DHCP client: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to start DHCP client: %s", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -511,14 +574,17 @@ esp_err_t wifi_use_dhcp(void)
|
|||||||
|
|
||||||
esp_err_t wifi_switch_mode(const char* mode)
|
esp_err_t wifi_switch_mode(const char* mode)
|
||||||
{
|
{
|
||||||
if (strcmp(mode, "sta") != 0 && strcmp(mode, "apsta") != 0) {
|
if (strcmp(mode, "sta") != 0 && strcmp(mode, "apsta") != 0)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Invalid mode specified: %s. Use 'sta' or 'apsta'.", mode);
|
ESP_LOGE(TAG, "Invalid mode specified: %s. Use 'sta' or 'apsta'.", mode);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
char current_mode_buf[16] = {0};
|
char current_mode_buf[16] = {0};
|
||||||
if (nconfig_read(WIFI_MODE, current_mode_buf, sizeof(current_mode_buf)) == ESP_OK) {
|
if (nconfig_read(WIFI_MODE, current_mode_buf, sizeof(current_mode_buf)) == ESP_OK)
|
||||||
if (strcmp(current_mode_buf, mode) == 0) {
|
{
|
||||||
|
if (strcmp(current_mode_buf, mode) == 0)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Already in %s mode.", mode);
|
ESP_LOGI(TAG, "Already in %s mode.", mode);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -527,14 +593,16 @@ esp_err_t wifi_switch_mode(const char* mode)
|
|||||||
ESP_LOGI(TAG, "Switching Wi-Fi mode to %s.", mode);
|
ESP_LOGI(TAG, "Switching Wi-Fi mode to %s.", mode);
|
||||||
|
|
||||||
esp_err_t err = nconfig_write(WIFI_MODE, mode);
|
esp_err_t err = nconfig_write(WIFI_MODE, mode);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to save new Wi-Fi mode to NVS");
|
ESP_LOGE(TAG, "Failed to save new Wi-Fi mode to NVS");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_disconnect();
|
wifi_disconnect();
|
||||||
err = wifi_connect();
|
err = wifi_connect();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to connect in new mode %s", mode);
|
ESP_LOGE(TAG, "Failed to connect in new mode %s", mode);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center control-list-item">
|
<li class="list-group-item d-flex justify-content-between align-items-center control-list-item">
|
||||||
Main Power (12V)
|
Main Power
|
||||||
<div class="control-wrapper">
|
<div class="control-wrapper">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="main-power-toggle">
|
<input class="form-check-input" type="checkbox" role="switch" id="main-power-toggle">
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center control-list-item">
|
<li class="list-group-item d-flex justify-content-between align-items-center control-list-item">
|
||||||
USB Power (5V)
|
USB Power
|
||||||
<div class="control-wrapper">
|
<div class="control-wrapper">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="usb-power-toggle">
|
<input class="form-check-input" type="checkbox" role="switch" id="usb-power-toggle">
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
<div class="d-flex justify-content-end mb-3">
|
<div class="d-flex justify-content-end mb-3">
|
||||||
<a href="/datalog.csv" class="btn btn-primary" download="datalog.csv"><i class="bi bi-download me-1"></i> Download CSV</a>
|
<a href="/datalog.csv" class="btn btn-primary" download="datalog.csv"><i class="bi bi-download me-1"></i> Download CSV</a>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="card-title text-center mb-3">Power Input</h5>
|
<h5 class="card-title text-center mb-3">Power Metrics</h5>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4 mb-3 mb-md-0">
|
<div class="col-md-4 mb-3 mb-md-0">
|
||||||
<canvas id="powerChart" class="chart-canvas"></canvas>
|
<canvas id="powerChart" class="chart-canvas"></canvas>
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
<div id="ap-mode-config" style="display: none;">
|
<div id="ap-mode-config" style="display: none;">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="ap-ssid" class="form-label">AP SSID</label>
|
<label for="ap-ssid" class="form-label">AP SSID</label>
|
||||||
<input type="text" class="form-control" id="ap-ssid" placeholder="ODROID-Remote-AP">
|
<input type="text" class="form-control" id="ap-ssid" placeholder="odroid-pm">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="ap-password" class="form-label">AP Password</label>
|
<label for="ap-password" class="form-label">AP Password</label>
|
||||||
@@ -278,6 +278,12 @@
|
|||||||
<option value="1500000" selected>1500000</option>
|
<option value="1500000" selected>1500000</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">System Reboot</label>
|
||||||
|
<p class="text-muted small">This will restart the device. The reboot will occur after 3 seconds.</p>
|
||||||
|
<button type="button" class="btn btn-danger" id="reboot-button">Reboot Now</button>
|
||||||
|
</div>
|
||||||
<div class="d-flex justify-content-end pt-3 border-top mt-3">
|
<div class="d-flex justify-content-end pt-3 border-top mt-3">
|
||||||
<button type="button" class="btn btn-primary me-2" id="baud-rate-apply-button">Apply</button>
|
<button type="button" class="btn btn-primary me-2" id="baud-rate-apply-button">Apply</button>
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
@@ -314,6 +320,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const rebootButton = document.getElementById('reboot-button');
|
||||||
|
if (rebootButton) {
|
||||||
|
rebootButton.addEventListener('click', () => {
|
||||||
|
if (confirm('Are you sure you want to reboot the device?')) {
|
||||||
|
fetch('/api/reboot', {
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('Reboot command sent:', data);
|
||||||
|
const settingsModalEl = document.getElementById('settingsModal');
|
||||||
|
const settingsModal = bootstrap.Modal.getInstance(settingsModalEl);
|
||||||
|
if (settingsModal) {
|
||||||
|
settingsModal.hide();
|
||||||
|
}
|
||||||
|
alert('Reboot command sent. The device will restart in 3 seconds.');
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error sending reboot command:', error);
|
||||||
|
alert('Failed to send reboot command.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -17,6 +17,7 @@ export const charts = {
|
|||||||
current: null
|
current: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const channelKeys = ['USB', 'MAIN', 'VIN'];
|
||||||
const CHART_DATA_POINTS = 30; // Number of data points to display on the chart
|
const CHART_DATA_POINTS = 30; // Number of data points to display on the chart
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +57,7 @@ function createChartOptions(title, minValue, maxValue) {
|
|||||||
y: {
|
y: {
|
||||||
min: minValue,
|
min: minValue,
|
||||||
max: maxValue,
|
max: maxValue,
|
||||||
beginAtZero: false,
|
beginAtZero: true, // Start at zero for better comparison
|
||||||
ticks: {
|
ticks: {
|
||||||
stepSize: (maxValue - minValue) / 8
|
stepSize: (maxValue - minValue) / 8
|
||||||
}
|
}
|
||||||
@@ -65,6 +66,23 @@ function createChartOptions(title, minValue, maxValue) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the dataset objects for a chart.
|
||||||
|
* @param {string} unit - The unit for the dataset label (e.g., 'W', 'V', 'A').
|
||||||
|
* @returns {Array<Object>} An array of Chart.js dataset objects.
|
||||||
|
*/
|
||||||
|
function createDatasets(unit) {
|
||||||
|
return channelKeys.map(channel => ({
|
||||||
|
label: `${channel} (${unit})`,
|
||||||
|
data: initialData(),
|
||||||
|
borderWidth: 2,
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2,
|
||||||
|
pointRadius: 2
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes all three charts (Power, Voltage, Current).
|
* Initializes all three charts (Power, Voltage, Current).
|
||||||
* If chart instances already exist, they are destroyed and new ones are created.
|
* If chart instances already exist, they are destroyed and new ones are created.
|
||||||
@@ -79,15 +97,12 @@ export function initCharts() {
|
|||||||
|
|
||||||
// Create Power Chart
|
// Create Power Chart
|
||||||
if (powerChartCtx) {
|
if (powerChartCtx) {
|
||||||
const powerOptions = createChartOptions('Power', 0, 120);
|
const powerOptions = createChartOptions('Power', 0, 50); // Adjusted max value
|
||||||
charts.power = new Chart(powerChartCtx, {
|
charts.power = new Chart(powerChartCtx, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: initialLabels(),
|
labels: initialLabels(),
|
||||||
datasets: [
|
datasets: createDatasets('W')
|
||||||
{ label: 'Power (W)', data: initialData(), borderWidth: 2, fill: false, tension: 0.2, pointRadius: 2 },
|
|
||||||
{ label: 'Avg Power', data: initialData(), borderWidth: 1.5, borderDash: [10, 5], fill: false, tension: 0, pointRadius: 0 }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
options: powerOptions
|
options: powerOptions
|
||||||
});
|
});
|
||||||
@@ -100,10 +115,7 @@ export function initCharts() {
|
|||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: initialLabels(),
|
labels: initialLabels(),
|
||||||
datasets: [
|
datasets: createDatasets('V')
|
||||||
{ label: 'Voltage (V)', data: initialData(), borderWidth: 2, fill: false, tension: 0.2, pointRadius: 2 },
|
|
||||||
{ label: 'Avg Voltage', data: initialData(), borderWidth: 1.5, borderDash: [10, 5], fill: false, tension: 0, pointRadius: 0 }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
options: voltageOptions
|
options: voltageOptions
|
||||||
});
|
});
|
||||||
@@ -111,15 +123,12 @@ export function initCharts() {
|
|||||||
|
|
||||||
// Create Current Chart
|
// Create Current Chart
|
||||||
if (currentChartCtx) {
|
if (currentChartCtx) {
|
||||||
const currentOptions = createChartOptions('Current', 0, 7);
|
const currentOptions = createChartOptions('Current', 0, 5); // Adjusted max value
|
||||||
charts.current = new Chart(currentChartCtx, {
|
charts.current = new Chart(currentChartCtx, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: initialLabels(),
|
labels: initialLabels(),
|
||||||
datasets: [
|
datasets: createDatasets('A')
|
||||||
{ label: 'Current (A)', data: initialData(), borderWidth: 2, fill: false, tension: 0.2, pointRadius: 2 },
|
|
||||||
{ label: 'Avg Current', data: initialData(), borderWidth: 1.5, borderDash: [10, 5], fill: false, tension: 0, pointRadius: 0 }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
options: currentOptions
|
options: currentOptions
|
||||||
});
|
});
|
||||||
@@ -135,11 +144,14 @@ export function applyChartsTheme(themeName) {
|
|||||||
const gridColor = isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
const gridColor = isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
||||||
const labelColor = isDark ? '#dee2e6' : '#212529';
|
const labelColor = isDark ? '#dee2e6' : '#212529';
|
||||||
|
|
||||||
const powerColor = getComputedStyle(htmlEl).getPropertyValue('--chart-power-color');
|
// Define colors for each channel. These could be from CSS variables.
|
||||||
const voltageColor = getComputedStyle(htmlEl).getPropertyValue('--chart-voltage-color');
|
const channelColors = [
|
||||||
const currentColor = getComputedStyle(htmlEl).getPropertyValue('--chart-current-color');
|
getComputedStyle(htmlEl).getPropertyValue('--chart-usb-color').trim() || '#0d6efd', // Blue
|
||||||
|
getComputedStyle(htmlEl).getPropertyValue('--chart-main-color').trim() || '#198754', // Green
|
||||||
|
getComputedStyle(htmlEl).getPropertyValue('--chart-vin-color').trim() || '#dc3545' // Red
|
||||||
|
];
|
||||||
|
|
||||||
const updateThemeForChart = (chart, color) => {
|
const updateThemeForChart = (chart) => {
|
||||||
if (!chart) return;
|
if (!chart) return;
|
||||||
chart.options.scales.x.grid.color = gridColor;
|
chart.options.scales.x.grid.color = gridColor;
|
||||||
chart.options.scales.y.grid.color = gridColor;
|
chart.options.scales.y.grid.color = gridColor;
|
||||||
@@ -147,15 +159,17 @@ export function applyChartsTheme(themeName) {
|
|||||||
chart.options.scales.y.ticks.color = labelColor;
|
chart.options.scales.y.ticks.color = labelColor;
|
||||||
chart.options.plugins.legend.labels.color = labelColor;
|
chart.options.plugins.legend.labels.color = labelColor;
|
||||||
chart.options.plugins.title.color = labelColor;
|
chart.options.plugins.title.color = labelColor;
|
||||||
chart.data.datasets[0].borderColor = color;
|
|
||||||
chart.data.datasets[1].borderColor = color;
|
chart.data.datasets.forEach((dataset, index) => {
|
||||||
chart.data.datasets[1].borderDash = [10, 5];
|
dataset.borderColor = channelColors[index];
|
||||||
|
});
|
||||||
|
|
||||||
chart.update('none');
|
chart.update('none');
|
||||||
};
|
};
|
||||||
|
|
||||||
updateThemeForChart(charts.power, powerColor);
|
updateThemeForChart(charts.power);
|
||||||
updateThemeForChart(charts.voltage, voltageColor);
|
updateThemeForChart(charts.voltage);
|
||||||
updateThemeForChart(charts.current, currentColor);
|
updateThemeForChart(charts.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,7 +179,7 @@ export function applyChartsTheme(themeName) {
|
|||||||
export function updateCharts(data) {
|
export function updateCharts(data) {
|
||||||
const timeLabel = new Date(data.timestamp * 1000).toLocaleTimeString();
|
const timeLabel = new Date(data.timestamp * 1000).toLocaleTimeString();
|
||||||
|
|
||||||
const updateSingleChart = (chart, value) => {
|
const updateSingleChart = (chart, metric) => {
|
||||||
if (!chart) return;
|
if (!chart) return;
|
||||||
|
|
||||||
// Shift old data
|
// Shift old data
|
||||||
@@ -174,18 +188,15 @@ export function updateCharts(data) {
|
|||||||
|
|
||||||
// Push new data
|
// Push new data
|
||||||
chart.data.labels.push(timeLabel);
|
chart.data.labels.push(timeLabel);
|
||||||
chart.data.datasets[0].data.push(value.toFixed(2));
|
|
||||||
|
|
||||||
// Calculate average
|
|
||||||
const dataArray = chart.data.datasets[0].data.filter(v => v !== null).map(v => parseFloat(v));
|
|
||||||
if (dataArray.length > 0) {
|
|
||||||
const sum = dataArray.reduce((acc, val) => acc + val, 0);
|
|
||||||
const avg = (sum / dataArray.length).toFixed(2);
|
|
||||||
chart.data.datasets[1].data.push(avg);
|
|
||||||
|
|
||||||
|
channelKeys.forEach((key, index) => {
|
||||||
|
if (data[key] && data[key][metric] !== undefined) {
|
||||||
|
const value = data[key][metric];
|
||||||
|
chart.data.datasets[index].data.push(value.toFixed(2));
|
||||||
} else {
|
} else {
|
||||||
chart.data.datasets[1].data.push(null);
|
chart.data.datasets[index].data.push(null); // Push null if data for a channel is missing
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Only update the chart if the tab is visible
|
// Only update the chart if the tab is visible
|
||||||
if (graphTabPane.classList.contains('show')) {
|
if (graphTabPane.classList.contains('show')) {
|
||||||
@@ -193,9 +204,9 @@ export function updateCharts(data) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateSingleChart(charts.power, data.power);
|
updateSingleChart(charts.power, 'power');
|
||||||
updateSingleChart(charts.voltage, data.voltage);
|
updateSingleChart(charts.voltage, 'voltage');
|
||||||
updateSingleChart(charts.current, data.current);
|
updateSingleChart(charts.current, 'current');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ function onWsOpen() {
|
|||||||
if (term) {
|
if (term) {
|
||||||
term.write('\x1b[32mConnected to WebSocket Server\x1b[0m\r\n');
|
term.write('\x1b[32mConnected to WebSocket Server\x1b[0m\r\n');
|
||||||
}
|
}
|
||||||
updateControlStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,6 +91,9 @@ function initialize() {
|
|||||||
const savedTheme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
const savedTheme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||||
applyTheme(savedTheme);
|
applyTheme(savedTheme);
|
||||||
|
|
||||||
|
// Fetch initial status on page load
|
||||||
|
updateControlStatus();
|
||||||
|
|
||||||
// Establish the WebSocket connection with the defined handlers
|
// Establish the WebSocket connection with the defined handlers
|
||||||
initWebSocket({
|
initWebSocket({
|
||||||
onOpen: onWsOpen,
|
onOpen: onWsOpen,
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bs-body-font-family: 'Courier New', Courier, monospace;
|
--bs-body-font-family: 'Courier New', Courier, monospace;
|
||||||
--chart-power-color: #007bff;
|
/* Chart Channel Colors */
|
||||||
--chart-voltage-color: #28a745;
|
--chart-usb-color: #0d6efd; /* Bootstrap Blue */
|
||||||
--chart-current-color: #ffc107;
|
--chart-main-color: #198754; /* Bootstrap Green */
|
||||||
|
--chart-vin-color: #dc3545; /* Bootstrap Red */
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-bs-theme="dark"] {
|
[data-bs-theme="dark"] {
|
||||||
--chart-power-color: #569cd6;
|
/* Chart Channel Colors for Dark Theme */
|
||||||
--chart-voltage-color: #4ec9b0;
|
--chart-usb-color: #569cd6; /* A lighter blue for dark backgrounds */
|
||||||
--chart-current-color: #dcdcaa;
|
--chart-main-color: #4ec9b0; /* A teal/cyan for dark backgrounds */
|
||||||
|
--chart-vin-color: #d16969; /* A softer red for dark backgrounds */
|
||||||
}
|
}
|
||||||
|
|
||||||
body, .card, .modal-content, .list-group-item, .nav-tabs .nav-link {
|
body, .card, .modal-content, .list-group-item, .nav-tabs .nav-link {
|
||||||
|
|||||||
@@ -40,12 +40,18 @@ export function applyTheme(themeName) {
|
|||||||
* @param {Object} data - The sensor data object from the WebSocket.
|
* @param {Object} data - The sensor data object from the WebSocket.
|
||||||
*/
|
*/
|
||||||
export function updateSensorUI(data) {
|
export function updateSensorUI(data) {
|
||||||
dom.voltageDisplay.textContent = `${data.voltage.toFixed(2)} V`;
|
// Display VIN channel data in the header as a primary overview
|
||||||
dom.currentDisplay.textContent = `${data.current.toFixed(2)} A`;
|
if (data.VIN) {
|
||||||
dom.powerDisplay.textContent = `${data.power.toFixed(2)} W`;
|
dom.voltageDisplay.textContent = `${data.VIN.voltage.toFixed(2)} V`;
|
||||||
|
dom.currentDisplay.textContent = `${data.VIN.current.toFixed(2)} A`;
|
||||||
|
dom.powerDisplay.textContent = `${data.VIN.power.toFixed(2)} W`;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.uptime_sec !== undefined) {
|
if (data.uptime_sec !== undefined) {
|
||||||
dom.uptimeDisplay.textContent = formatUptime(data.uptime_sec);
|
dom.uptimeDisplay.textContent = formatUptime(data.uptime_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass the entire multi-channel data object to the charts
|
||||||
updateCharts(data);
|
updateCharts(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user