commit
33ae8b7294
35 changed files with 1345 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||||
|
build |
||||
|
sdkconfig |
||||
|
sdkconfig.old |
||||
|
|
||||
|
# Used during development to test OTA |
||||
|
# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system.html |
||||
|
version.txt |
||||
@ -0,0 +1,8 @@ |
|||||
|
[submodule "esp32-owb"] |
||||
|
path = components/esp32-owb |
||||
|
url = https://github.com/DavidAntliff/esp32-owb.git |
||||
|
branch = master |
||||
|
[submodule "esp32-ds18b20"] |
||||
|
path = components/esp32-ds18b20 |
||||
|
url = https://github.com/DavidAntliff/esp32-ds18b20.git |
||||
|
branch = master |
||||
@ -0,0 +1,8 @@ |
|||||
|
# The following lines of boilerplate have to be in your project's CMakeLists |
||||
|
# in this exact order for cmake to work correctly |
||||
|
cmake_minimum_required(VERSION 3.5) |
||||
|
|
||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake) |
||||
|
project(solar_controller) |
||||
|
|
||||
|
target_add_binary_data(solar_controller.elf "main/cacert.pem" TEXT) |
||||
@ -0,0 +1,8 @@ |
|||||
|
#
|
||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
|
# project subdirectory.
|
||||
|
#
|
||||
|
|
||||
|
PROJECT_NAME := solar_controller |
||||
|
|
||||
|
include $(IDF_PATH)/make/project.mk |
||||
@ -0,0 +1,2 @@ |
|||||
|
# Solar Controller |
||||
|
|
||||
@ -0,0 +1,2 @@ |
|||||
|
idf_component_register(SRCS "main.c" "solar.c" "wifi.c" "mqtt.c" "sntp.c" "common.c" "ota.c" |
||||
|
INCLUDE_DIRS ".") |
||||
@ -0,0 +1,111 @@ |
|||||
|
menu "Solar controller configuration" |
||||
|
|
||||
|
config SC_1WIRE_GPIO |
||||
|
int "GPIO number for the 1-wire bus" |
||||
|
range 0 34 if IDF_TARGET_ESP32 |
||||
|
range 0 46 if IDF_TARGET_ESP32S2 |
||||
|
range 0 19 if IDF_TARGET_ESP32C3 |
||||
|
default 4 |
||||
|
help |
||||
|
GPIO number for the 1-wire bus. |
||||
|
|
||||
|
config SC_SAMPLE_PERIOD |
||||
|
int "Number of seconds between readings." |
||||
|
range 1 3600 |
||||
|
default 1 |
||||
|
help |
||||
|
Number of seconds between readings. |
||||
|
|
||||
|
config SC_PANEL_PUMP_GPIO |
||||
|
int "PIN used to send PWM signal to the panel pump." |
||||
|
range 0 34 if IDF_TARGET_ESP32 |
||||
|
range 0 46 if IDF_TARGET_ESP32S2 |
||||
|
range 0 19 if IDF_TARGET_ESP32C3 |
||||
|
default 19 |
||||
|
help |
||||
|
GPIO number for the panel pump. |
||||
|
|
||||
|
config SC_FLOOR_HEATING_PUMP_GPIO |
||||
|
int "PIN used to send PWM signal to the floor heating pump." |
||||
|
range 0 34 if IDF_TARGET_ESP32 |
||||
|
range 0 46 if IDF_TARGET_ESP32S2 |
||||
|
range 0 19 if IDF_TARGET_ESP32C3 |
||||
|
default 21 |
||||
|
help |
||||
|
GPIO number for the floor heating pump. |
||||
|
|
||||
|
config SC_PUMP_PWM_FREQ |
||||
|
int "PWM Frequency used to drive both pumps." |
||||
|
range 1000 10000 |
||||
|
default 1000 |
||||
|
help |
||||
|
PWM Frequency used to drive both pumps. |
||||
|
|
||||
|
config SC_STACK_SIZE |
||||
|
int "Stack size for the solar controller." |
||||
|
range 1024 16384 |
||||
|
default 4096 |
||||
|
help |
||||
|
Defines stack size. Insufficient stack size can cause crash. |
||||
|
|
||||
|
config SC_FROST_PROTECTION_TEMP_LOW |
||||
|
int "Frost protection temperature (lower bound)." |
||||
|
range -30 100 |
||||
|
default -4 |
||||
|
help |
||||
|
If the temperature is lower, starts the panel pump. |
||||
|
|
||||
|
config SC_FROST_PROTECTION_TEMP_HIGH |
||||
|
int "Frost protection temperature (higher bound)." |
||||
|
range -30 100 |
||||
|
default 1 |
||||
|
help |
||||
|
If the temperature is higher, stops the panel pump. |
||||
|
|
||||
|
config SC_PANEL_DELTA_TEMP_LOW |
||||
|
int "Difference of temperature at which the panel pump stops (lower bound)." |
||||
|
range -30 100 |
||||
|
default 5 |
||||
|
help |
||||
|
If the temperature is lower, starts the panel pump. |
||||
|
|
||||
|
config SC_PANEL_DELTA_TEMP_HIGH |
||||
|
int "Difference of temperature at which the panel pump starts (higher bound)." |
||||
|
range -30 100 |
||||
|
default 10 |
||||
|
help |
||||
|
If the temperature is higher, stops the panel pump. |
||||
|
|
||||
|
config SC_FLOOR_HEATING_DELTA_TEMP_LOW |
||||
|
int "Difference of temperature at which the floor heating pump stops (lower bound)." |
||||
|
range -30 100 |
||||
|
default 5 |
||||
|
help |
||||
|
If the temperature is lower, starts the panel pump. |
||||
|
|
||||
|
config SC_FLOOR_HEATING_DELTA_TEMP_HIGH |
||||
|
int "Difference of temperature at which the floor heating pump starts (higher bound)." |
||||
|
range -30 100 |
||||
|
default 7 |
||||
|
help |
||||
|
If the temperature is higher, stops the panel pump. |
||||
|
|
||||
|
config MQTT_LWT_TOPIC |
||||
|
string "MQTT Last Will Testament Topic" |
||||
|
default "solar-controller/connected" |
||||
|
help |
||||
|
Topic where to send LWT (Last Will Testament) upon disconnect. |
||||
|
|
||||
|
config MQTT_COMMAND_TOPIC |
||||
|
string "MQTT system command Topic" |
||||
|
default "solar-controller/command" |
||||
|
help |
||||
|
Topic where to send system commands. |
||||
|
|
||||
|
config MQTT_SOLAR_VALUE_TOPIC |
||||
|
string "Where to send measures" |
||||
|
default "solar-controller/status/solar/%s" |
||||
|
help |
||||
|
Topic where to measures. |
||||
|
|
||||
|
endmenu |
||||
@ -0,0 +1,27 @@ |
|||||
|
-----BEGIN CERTIFICATE----- |
||||
|
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE |
||||
|
BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD |
||||
|
EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG |
||||
|
EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT |
||||
|
DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r |
||||
|
Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 |
||||
|
3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K |
||||
|
b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN |
||||
|
Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ |
||||
|
4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf |
||||
|
1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu |
||||
|
hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH |
||||
|
usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r |
||||
|
OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G |
||||
|
A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY |
||||
|
9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL |
||||
|
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV |
||||
|
0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt |
||||
|
hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw |
||||
|
TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx |
||||
|
e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA |
||||
|
JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD |
||||
|
YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n |
||||
|
JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ |
||||
|
m+kXQ99b21/+jh5Xos1AnX5iItreGCc= |
||||
|
-----END CERTIFICATE----- |
||||
@ -0,0 +1,20 @@ |
|||||
|
#include "common.h" |
||||
|
volatile EventGroupHandle_t services_event_group; |
||||
|
|
||||
|
char* get_nvs_string(nvs_handle_t nvs, char* key) { |
||||
|
size_t required_size; |
||||
|
esp_err_t err = nvs_get_str(nvs, key, NULL, &required_size); |
||||
|
if (err != ESP_OK) { |
||||
|
return NULL; |
||||
|
} |
||||
|
char* value = malloc(required_size); |
||||
|
if (!value) { |
||||
|
return NULL; |
||||
|
} |
||||
|
err = nvs_get_str(nvs, key, value, &required_size); |
||||
|
if (err != ESP_OK) { |
||||
|
free(value); |
||||
|
return NULL; |
||||
|
} |
||||
|
return value; |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
#ifndef __COMMON_H__ |
||||
|
#define __COMMON_H__ |
||||
|
|
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "freertos/event_groups.h" |
||||
|
#include "nvs_flash.h" |
||||
|
#include "nvs.h" |
||||
|
|
||||
|
#define WIFI_CONNECTED_BIT BIT0 |
||||
|
#define MQTT_CONNECTED_BIT BIT1 |
||||
|
#define TIME_SYNC_BIT BIT2 |
||||
|
|
||||
|
extern volatile EventGroupHandle_t services_event_group; |
||||
|
char* get_nvs_string(nvs_handle_t nvs, char* key); |
||||
|
|
||||
|
#define WAIT_FOR(flags) while ((xEventGroupWaitBits(services_event_group, flags, pdFALSE, pdTRUE, portMAX_DELAY) & (flags)) != (flags)) {} |
||||
|
#define IS_READY(flags) ((xEventGroupGetBits(services_event_group) & (flags)) == (flags)) |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,4 @@ |
|||||
|
#
|
||||
|
# Main Makefile. This is basically the same as a component makefile.
|
||||
|
#
|
||||
|
COMPONENT_EMBED_TXTFILES := cacert.pem |
||||
@ -0,0 +1,48 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "freertos/queue.h" |
||||
|
#include "driver/uart.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "nvs_flash.h" |
||||
|
#include "nvs.h" |
||||
|
#include "esp_tls.h" |
||||
|
#include "esp_crt_bundle.h" |
||||
|
#include "wifi.h" |
||||
|
#include "mqtt.h" |
||||
|
#include "solar.h" |
||||
|
#include "sntp.h" |
||||
|
#include "common.h" |
||||
|
#include "esp_ota_ops.h" |
||||
|
#include "ota.h" |
||||
|
|
||||
|
// Embedded via component.mk
|
||||
|
extern const uint8_t cacert_pem_start[] asm("_binary_cacert_pem_start"); |
||||
|
extern const uint8_t cacert_pem_end[] asm("_binary_cacert_pem_end"); |
||||
|
|
||||
|
void app_main(void) { |
||||
|
const esp_app_desc_t* current = esp_ota_get_app_description(); |
||||
|
ESP_LOGI("main", "Currently running %s version %s", current->project_name, current->version); |
||||
|
|
||||
|
// NVS is used to store wifi credentials. So, we need to initialize it first.
|
||||
|
ESP_ERROR_CHECK(nvs_flash_init()); |
||||
|
|
||||
|
// Inject the Let's Encrypt Root CA certificate in the global CA store
|
||||
|
ESP_ERROR_CHECK(esp_tls_init_global_ca_store()); |
||||
|
ESP_ERROR_CHECK(esp_tls_set_global_ca_store((const unsigned char *) cacert_pem_start, cacert_pem_end - cacert_pem_start)); |
||||
|
|
||||
|
// Create an event group to keep track of service readiness
|
||||
|
services_event_group = xEventGroupCreate(); |
||||
|
|
||||
|
// Start the solar controller early because we need it working even in case
|
||||
|
// of missing wifi network.
|
||||
|
solar_init(); |
||||
|
|
||||
|
// Then connect to Wifi, MQTT and NTP
|
||||
|
wifi_init_sta(); |
||||
|
WAIT_FOR(WIFI_CONNECTED_BIT); |
||||
|
mqtt_init(); |
||||
|
sntp_start(); |
||||
|
WAIT_FOR(MQTT_CONNECTED_BIT|TIME_SYNC_BIT); |
||||
|
} |
||||
@ -0,0 +1,242 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdint.h> |
||||
|
#include <stddef.h> |
||||
|
#include <string.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "esp_system.h" |
||||
|
#include "nvs_flash.h" |
||||
|
#include "esp_event.h" |
||||
|
#include "esp_netif.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "mqtt_client.h" |
||||
|
#include "esp_tls.h" |
||||
|
#include "esp_ota_ops.h" |
||||
|
#include <sys/param.h> |
||||
|
#include <time.h> |
||||
|
#include "cJSON.h" |
||||
|
#include "common.h" |
||||
|
#include "ota.h" |
||||
|
#include "mqtt.h" |
||||
|
#include "solar.h" |
||||
|
|
||||
|
static esp_mqtt_client_config_t mqtt_cfg; |
||||
|
static esp_mqtt_client_handle_t client; |
||||
|
|
||||
|
static const char *MQTT_LOGGER = "mqtt"; |
||||
|
|
||||
|
#define MQTT_QOS_0 0 |
||||
|
#define MQTT_QOS_1 1 |
||||
|
#define MQTT_QOS_2 2 |
||||
|
|
||||
|
#define MQTT_NO_RETAIN 0 |
||||
|
#define MQTT_RETAIN 1 |
||||
|
|
||||
|
#define JSON_BUFFER_SIZE 128 |
||||
|
#define MQTT_TOPIC_BUFFER_SIZE 128 |
||||
|
|
||||
|
#define SYSTEM_COMMAND_UPDATE "firmware-update" |
||||
|
#define SYSTEM_COMMAND_REBOOT "reboot" |
||||
|
#define SYSTEM_COMMAND_SET_PARAM "set-parameter" |
||||
|
#define PARAMETER_HEATING_ENABLED "heating_enabled" |
||||
|
|
||||
|
void mqtt_publish_data(char* key, json_value jv) { |
||||
|
char topic[MQTT_TOPIC_BUFFER_SIZE]; |
||||
|
char payload[JSON_BUFFER_SIZE]; |
||||
|
time_t now; |
||||
|
int retain = MQTT_RETAIN; |
||||
|
int qos = MQTT_QOS_1; |
||||
|
|
||||
|
// Format the MQTT topic
|
||||
|
if (!snprintf(topic, MQTT_TOPIC_BUFFER_SIZE, CONFIG_MQTT_SOLAR_VALUE_TOPIC, key)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "mqtt_publish_data: snprintf failed!"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
cJSON *root = cJSON_CreateObject(); |
||||
|
if (root == NULL) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "mqtt_publish_data: cJSON_CreateObject failed!"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Add the value
|
||||
|
if (jv.type == MQTT_TYPE_STRING) { |
||||
|
cJSON_AddStringToObject(root, "val", (char*)jv.value.str); |
||||
|
} else if (jv.type == MQTT_TYPE_FLOAT) { |
||||
|
float f = jv.value.f; |
||||
|
cJSON_AddNumberToObject(root, "val", (double)f); |
||||
|
} else if (jv.type == MQTT_TYPE_INT) { |
||||
|
int i = jv.value.i; |
||||
|
cJSON_AddNumberToObject(root, "val", (double)i); |
||||
|
} |
||||
|
|
||||
|
// Add a timestamp
|
||||
|
time(&now); |
||||
|
cJSON_AddNumberToObject(root, "ts", (double)now); |
||||
|
|
||||
|
if (!cJSON_PrintPreallocated(root, payload, JSON_BUFFER_SIZE, 0)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "mqtt_publish_data: cJSON_PrintPreallocated failed!"); |
||||
|
cJSON_Delete(root); |
||||
|
return; |
||||
|
} |
||||
|
cJSON_Delete(root); |
||||
|
|
||||
|
if (esp_mqtt_client_publish(client, topic, payload, 0, qos, retain) == -1) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "MQTT Message discarded!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
esp_err_t mqtt_process_system_command(char* data, int data_len) { |
||||
|
esp_err_t status = ESP_OK; |
||||
|
cJSON *json = cJSON_ParseWithLength(data, data_len); |
||||
|
if (json == NULL) { |
||||
|
ESP_LOGI(MQTT_LOGGER, "Error parsing MQTT system command as JSON"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
cJSON* command = cJSON_GetObjectItemCaseSensitive(json, "command"); |
||||
|
if (!cJSON_IsString(command) || (command->valuestring == NULL)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Expected a command name!"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
if (strcmp(command->valuestring, SYSTEM_COMMAND_REBOOT) == 0) { |
||||
|
ESP_LOGE(MQTT_LOGGER, "Received a reboot command. Rebooting now!"); |
||||
|
esp_restart(); |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
if (strcmp(command->valuestring, SYSTEM_COMMAND_UPDATE) == 0) { |
||||
|
cJSON* args = cJSON_GetObjectItemCaseSensitive(json, "args"); |
||||
|
if (!cJSON_IsObject(args)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Expected a command argument!"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
cJSON* version = cJSON_GetObjectItemCaseSensitive(args, "version"); |
||||
|
if (!cJSON_IsString(version) || (version->valuestring == NULL)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Expected a version numer!"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
trigger_ota_update(version->valuestring); |
||||
|
goto end; |
||||
|
} else if (strcmp(command->valuestring, SYSTEM_COMMAND_SET_PARAM) == 0) { |
||||
|
cJSON* args = cJSON_GetObjectItemCaseSensitive(json, "args"); |
||||
|
if (!cJSON_IsObject(args)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Expected a command argument!"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
cJSON* name = cJSON_GetObjectItemCaseSensitive(args, "name"); |
||||
|
if (!cJSON_IsString(name) || (name->valuestring == NULL)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Expected a parameter name!"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
char * param_name = name->valuestring; |
||||
|
if (strcmp(param_name, PARAMETER_HEATING_ENABLED) == 0) { |
||||
|
cJSON* value = cJSON_GetObjectItemCaseSensitive(args, "value"); |
||||
|
if (!cJSON_IsNumber(value)) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Expected a parameter value with type 'number'!"); |
||||
|
status = ESP_FAIL; |
||||
|
goto end; |
||||
|
} |
||||
|
int heating_enabled = value->valuedouble; |
||||
|
solar_set_heating(heating_enabled); |
||||
|
} |
||||
|
|
||||
|
goto end; |
||||
|
} |
||||
|
|
||||
|
ESP_LOGW(MQTT_LOGGER, "Unknown system command %s!", command->valuestring); |
||||
|
status = ESP_FAIL; |
||||
|
|
||||
|
end: |
||||
|
cJSON_Delete(json); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { |
||||
|
switch (event->event_id) { |
||||
|
case MQTT_EVENT_CONNECTED: |
||||
|
ESP_LOGI(MQTT_LOGGER, "MQTT_EVENT_CONNECTED"); |
||||
|
xEventGroupSetBits(services_event_group, MQTT_CONNECTED_BIT); |
||||
|
if (esp_mqtt_client_publish(client, CONFIG_MQTT_LWT_TOPIC, "1", 0, MQTT_QOS_0, MQTT_RETAIN) == -1) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "MQTT Message discarded!"); |
||||
|
} |
||||
|
if (esp_mqtt_client_subscribe(client, CONFIG_MQTT_COMMAND_TOPIC, MQTT_QOS_1) == -1) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Could not subscribe to " CONFIG_MQTT_COMMAND_TOPIC " MQTT topic"); |
||||
|
} |
||||
|
break; |
||||
|
case MQTT_EVENT_DISCONNECTED: |
||||
|
ESP_LOGI(MQTT_LOGGER, "MQTT_EVENT_DISCONNECTED"); |
||||
|
xEventGroupClearBits(services_event_group, MQTT_CONNECTED_BIT); |
||||
|
break; |
||||
|
case MQTT_EVENT_PUBLISHED: |
||||
|
ESP_LOGD(MQTT_LOGGER, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); |
||||
|
break; |
||||
|
case MQTT_EVENT_ERROR: |
||||
|
ESP_LOGI(MQTT_LOGGER, "MQTT_EVENT_ERROR"); |
||||
|
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { |
||||
|
ESP_LOGI(MQTT_LOGGER, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err); |
||||
|
ESP_LOGI(MQTT_LOGGER, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err); |
||||
|
ESP_LOGI(MQTT_LOGGER, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno, |
||||
|
strerror(event->error_handle->esp_transport_sock_errno)); |
||||
|
} else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) { |
||||
|
ESP_LOGI(MQTT_LOGGER, "Connection refused error: 0x%x", event->error_handle->connect_return_code); |
||||
|
} else { |
||||
|
ESP_LOGW(MQTT_LOGGER, "Unknown error type: 0x%x", event->error_handle->error_type); |
||||
|
} |
||||
|
break; |
||||
|
case MQTT_EVENT_DATA: |
||||
|
if (strncmp(event->topic, CONFIG_MQTT_COMMAND_TOPIC, event->topic_len) == 0) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Received an MQTT system command!"); |
||||
|
mqtt_process_system_command(event->data, event->data_len); |
||||
|
} |
||||
|
break; |
||||
|
case MQTT_EVENT_SUBSCRIBED: |
||||
|
// Expected event. Nothing to do.
|
||||
|
break; |
||||
|
default: |
||||
|
ESP_LOGD(MQTT_LOGGER, "Other event id:%d", event->event_id); |
||||
|
break; |
||||
|
} |
||||
|
return ESP_OK; |
||||
|
} |
||||
|
|
||||
|
void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { |
||||
|
ESP_LOGD(MQTT_LOGGER, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); |
||||
|
mqtt_event_handler_cb(event_data); |
||||
|
} |
||||
|
|
||||
|
void mqtt_init(void) { |
||||
|
nvs_handle_t nvs; |
||||
|
esp_err_t err = nvs_open("mqtt", NVS_READONLY, &nvs); |
||||
|
if (err != ESP_OK) { |
||||
|
ESP_LOGE(MQTT_LOGGER, "Error (%s) opening NVS handle!\n", esp_err_to_name(err)); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
memset(&mqtt_cfg, 0, sizeof(mqtt_cfg)); |
||||
|
mqtt_cfg.uri = get_nvs_string(nvs, "url"); |
||||
|
mqtt_cfg.use_global_ca_store = true; |
||||
|
mqtt_cfg.username = get_nvs_string(nvs, "username"); |
||||
|
mqtt_cfg.password = get_nvs_string(nvs, "password"); |
||||
|
mqtt_cfg.lwt_topic = CONFIG_MQTT_LWT_TOPIC; |
||||
|
mqtt_cfg.lwt_msg = "0"; |
||||
|
mqtt_cfg.lwt_qos = MQTT_QOS_0; |
||||
|
mqtt_cfg.lwt_retain = MQTT_RETAIN; |
||||
|
|
||||
|
nvs_close(nvs); |
||||
|
|
||||
|
client = esp_mqtt_client_init(&mqtt_cfg); |
||||
|
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client); |
||||
|
esp_mqtt_client_start(client); |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
#ifndef __MQTT_H__ |
||||
|
#define __MQTT_H__ |
||||
|
|
||||
|
#define MQTT_TYPE_UNDEFINED 0 |
||||
|
#define MQTT_TYPE_STRING 1 |
||||
|
#define MQTT_TYPE_INT 2 |
||||
|
#define MQTT_TYPE_FLOAT 3 |
||||
|
|
||||
|
typedef struct { |
||||
|
int type; |
||||
|
union { |
||||
|
char* str; |
||||
|
float f; |
||||
|
int i; |
||||
|
} value; |
||||
|
} json_value; |
||||
|
|
||||
|
|
||||
|
void mqtt_init(); |
||||
|
void mqtt_publish_data(char* key, json_value value); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,94 @@ |
|||||
|
#include <string.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "esp_https_ota.h" |
||||
|
#include "esp_ota_ops.h" |
||||
|
#include "ota.h" |
||||
|
#include "nvs_flash.h" |
||||
|
#include "nvs.h" |
||||
|
#include "common.h" |
||||
|
|
||||
|
static const char *OTA_LOGGER = "ota_update"; |
||||
|
|
||||
|
// Embedded via component.mk
|
||||
|
extern const uint8_t cacert_pem_start[] asm("_binary_cacert_pem_start"); |
||||
|
extern const uint8_t cacert_pem_end[] asm("_binary_cacert_pem_end"); |
||||
|
|
||||
|
esp_err_t do_firmware_upgrade(char* firmware_url) { |
||||
|
esp_http_client_config_t config = { |
||||
|
.url = firmware_url, |
||||
|
.cert_pem = (char *)cacert_pem_start, |
||||
|
}; |
||||
|
|
||||
|
esp_https_ota_config_t ota_config = { |
||||
|
// Can be enabled in an upcoming version of the Espressif SDK
|
||||
|
// to save some memory.
|
||||
|
// Requires CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=4096 in sdkconfig.
|
||||
|
//
|
||||
|
//.partial_http_download = true,
|
||||
|
//.max_http_request_size = 4096,
|
||||
|
.http_config = &config, |
||||
|
}; |
||||
|
|
||||
|
esp_https_ota_handle_t https_ota_handle = NULL; |
||||
|
esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle); |
||||
|
if (https_ota_handle == NULL) { |
||||
|
return ESP_FAIL; |
||||
|
} |
||||
|
|
||||
|
while (1) { |
||||
|
err = esp_https_ota_perform(https_ota_handle); |
||||
|
if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (err != ESP_OK) { |
||||
|
esp_https_ota_abort(https_ota_handle); |
||||
|
return err; |
||||
|
} |
||||
|
|
||||
|
esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle); |
||||
|
if (ota_finish_err != ESP_OK) { |
||||
|
return ota_finish_err; |
||||
|
} |
||||
|
|
||||
|
esp_restart(); // this function never returns
|
||||
|
|
||||
|
return ESP_OK; |
||||
|
} |
||||
|
|
||||
|
void trigger_ota_update(char* version) { |
||||
|
const esp_app_desc_t* current = esp_ota_get_app_description(); |
||||
|
ESP_LOGD(OTA_LOGGER, "Currently running %s version %s", current->project_name, current->version); |
||||
|
|
||||
|
if (strcmp(version, current->version) == 0) { |
||||
|
// already to latest version
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
nvs_handle_t nvs; |
||||
|
esp_err_t err = nvs_open("ota", NVS_READONLY, &nvs); |
||||
|
if (err != ESP_OK) { |
||||
|
ESP_LOGE(OTA_LOGGER, "Error (%s) opening NVS handle!\n", esp_err_to_name(err)); |
||||
|
return; |
||||
|
} |
||||
|
char* update_url_pattern = get_nvs_string(nvs, "update_url"); |
||||
|
nvs_close(nvs); |
||||
|
if (update_url_pattern == NULL) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const size_t buffer_size = 256; |
||||
|
char update_url[buffer_size]; |
||||
|
|
||||
|
// Format the update URL
|
||||
|
if (!snprintf(update_url, buffer_size, update_url_pattern, version)) { |
||||
|
ESP_LOGD(OTA_LOGGER, "trigger_ota_update: snprintf failed!"); |
||||
|
free(update_url_pattern); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
esp_err_t ret = do_firmware_upgrade(update_url); |
||||
|
ESP_LOGW(OTA_LOGGER, "do_firmware_upgrade failed with error %d", ret); |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
#ifndef __OTA_H__ |
||||
|
#define __OTA_H__ |
||||
|
|
||||
|
void trigger_ota_update(char* version); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,38 @@ |
|||||
|
#include <string.h> |
||||
|
#include <time.h> |
||||
|
#include <sys/time.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "esp_system.h" |
||||
|
#include "esp_event.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "esp_attr.h" |
||||
|
#include "esp_sntp.h" |
||||
|
#include "sntp.h" |
||||
|
#include "common.h" |
||||
|
|
||||
|
static const char *SNTP_LOGGER = "sntp"; |
||||
|
|
||||
|
void sntp_callback(struct timeval *tv) { |
||||
|
if (sntp_get_sync_mode() == SNTP_SYNC_MODE_IMMED) { |
||||
|
time_t now; |
||||
|
time(&now); |
||||
|
struct tm now_tm; |
||||
|
localtime_r(&now, &now_tm); |
||||
|
char strftime_buf[64]; |
||||
|
if (strftime(strftime_buf, sizeof(strftime_buf), "%c", &now_tm)) { |
||||
|
ESP_LOGI(SNTP_LOGGER, "Time synchronized: %s", strftime_buf); |
||||
|
} |
||||
|
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); |
||||
|
xEventGroupSetBits(services_event_group, TIME_SYNC_BIT); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void sntp_start() { |
||||
|
ESP_LOGI(SNTP_LOGGER, "Initializing SNTP..."); |
||||
|
sntp_setoperatingmode(SNTP_OPMODE_POLL); |
||||
|
sntp_setservername(0, "pool.ntp.org"); |
||||
|
sntp_set_time_sync_notification_cb(sntp_callback); |
||||
|
sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED); |
||||
|
sntp_init(); |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
#ifndef __SNTP_H__ |
||||
|
#define __SNTP_H__ |
||||
|
|
||||
|
void sntp_start(); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,299 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "solar.h" |
||||
|
#include "mqtt.h" |
||||
|
#include "common.h" |
||||
|
|
||||
|
// 1-Wire support
|
||||
|
#include "owb.h" |
||||
|
#include "owb_rmt.h" |
||||
|
#include "ds18b20.h" |
||||
|
|
||||
|
// PWM support
|
||||
|
#include "driver/gpio.h" |
||||
|
#include "driver/ledc.h" |
||||
|
|
||||
|
#define SC_MAX_TEMPERATURE_SENSORS_COUNT 8 |
||||
|
#define SC_EXPECTED_TEMPERATURE_SENSORS_COUNT 4 |
||||
|
|
||||
|
#define SC_PUMP_FULL_POWER 255 |
||||
|
#define SC_PUMP_HALF_POWER 150 |
||||
|
#define SC_PUMP_NO_POWER 0 |
||||
|
|
||||
|
#define SC_LEDC_CHANNEL_PANEL_PUMP LEDC_CHANNEL_0 |
||||
|
#define SC_LEDC_CHANNEL_FLOOR_HEATING_PUMP LEDC_CHANNEL_1 |
||||
|
|
||||
|
static const char *SOLAR_LOGGER = "solar"; |
||||
|
static DS18B20_Info temperature_sensors[SC_EXPECTED_TEMPERATURE_SENSORS_COUNT]; |
||||
|
static int panel; |
||||
|
static int store_high; |
||||
|
static int store_low; |
||||
|
static int floor_heating; |
||||
|
static OneWireBus * owb; |
||||
|
static owb_rmt_driver_info rmt_driver_info; |
||||
|
static int is_heating_enabled = 0; |
||||
|
|
||||
|
void solar_set_heating(int enabled) { |
||||
|
is_heating_enabled = enabled; |
||||
|
|
||||
|
if (IS_READY(MQTT_CONNECTED_BIT|TIME_SYNC_BIT)) { |
||||
|
mqtt_publish_data("floor_heating_enabled", (json_value){MQTT_TYPE_INT, {.i = is_heating_enabled}}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static int map_pwm(float delta_temp) { |
||||
|
float res = delta_temp * 10.2; |
||||
|
|
||||
|
if (res > 255) { |
||||
|
return 255; |
||||
|
} |
||||
|
|
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static void solar_process(void *pvParameters) { |
||||
|
TickType_t last_wake_time = xTaskGetTickCount(); |
||||
|
int is_protecting_from_frost = 0; |
||||
|
int is_loading = 0; |
||||
|
int is_heating = 0; |
||||
|
int panel_pump_pwm = 0; |
||||
|
int floor_heating_pump_pwm = 0; |
||||
|
|
||||
|
int errors_count[SC_EXPECTED_TEMPERATURE_SENSORS_COUNT] = {0}; |
||||
|
for (;;) { |
||||
|
float readings[SC_EXPECTED_TEMPERATURE_SENSORS_COUNT]; |
||||
|
DS18B20_ERROR errors[SC_EXPECTED_TEMPERATURE_SENSORS_COUNT] = { 0 }; |
||||
|
|
||||
|
// Read temperatures more efficiently by starting conversions on all devices at the same time
|
||||
|
ds18b20_convert_all(owb); |
||||
|
|
||||
|
// In this application all devices use the same resolution,
|
||||
|
// so use the first device to determine the delay
|
||||
|
ds18b20_wait_for_conversion(&temperature_sensors[0]); |
||||
|
|
||||
|
|
||||
|
// Read the results immediately after conversion otherwise it may fail
|
||||
|
// (using printf before reading may take too long)
|
||||
|
for (int i = 0; i < SC_EXPECTED_TEMPERATURE_SENSORS_COUNT; ++i) { |
||||
|
errors[i] = ds18b20_read_temp(&temperature_sensors[i], &readings[i]); |
||||
|
} |
||||
|
|
||||
|
// Check if there are errors during measure or data transmission
|
||||
|
int has_reading_errors = 0; |
||||
|
for (int i = 0; i < SC_EXPECTED_TEMPERATURE_SENSORS_COUNT; ++i) { |
||||
|
if (errors[i] != DS18B20_OK) { |
||||
|
char rom_code_s[17]; |
||||
|
owb_string_from_rom_code(temperature_sensors[i].rom_code, rom_code_s, sizeof(rom_code_s)); |
||||
|
ESP_LOGW(SOLAR_LOGGER, "Error reading sensor %s.", rom_code_s); |
||||
|
++errors_count[i]; |
||||
|
has_reading_errors = 1; |
||||
|
} |
||||
|
} |
||||
|
// And retry a measure if there were errors
|
||||
|
if (has_reading_errors) { |
||||
|
ESP_LOGW(SOLAR_LOGGER, "There were errors while reading sensors. Retrying!"); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
float delta_panel = readings[panel] - readings[store_low]; |
||||
|
float delta_floor_heating = readings[store_high] - readings[floor_heating]; |
||||
|
|
||||
|
if (!is_protecting_from_frost && readings[panel] < CONFIG_SC_FROST_PROTECTION_TEMP_LOW) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Temperature is running low in the panel (%.1f), engaging frost protection!", readings[panel]); |
||||
|
is_protecting_from_frost = 1; |
||||
|
panel_pump_pwm = SC_PUMP_HALF_POWER; |
||||
|
} else if (is_protecting_from_frost && readings[panel] > CONFIG_SC_FROST_PROTECTION_TEMP_HIGH) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Disengaging frost protection..."); |
||||
|
is_protecting_from_frost = 0; |
||||
|
panel_pump_pwm = SC_PUMP_NO_POWER; |
||||
|
} else if (!is_loading && delta_panel > CONFIG_SC_PANEL_DELTA_TEMP_HIGH) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Start loading heat from the panel to the store..."); |
||||
|
panel_pump_pwm = map_pwm(delta_panel); |
||||
|
is_loading = 1; |
||||
|
} else if (is_loading && delta_panel < CONFIG_SC_PANEL_DELTA_TEMP_LOW) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Stop loading heat from the panel to the store..."); |
||||
|
panel_pump_pwm = SC_PUMP_NO_POWER; |
||||
|
is_loading = 0; |
||||
|
} else if (is_loading) { |
||||
|
// Keep adjusting the pump duty cycle according to the temperature difference
|
||||
|
panel_pump_pwm = map_pwm(delta_panel); |
||||
|
} |
||||
|
|
||||
|
if (is_heating && !is_heating_enabled) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Stop heating the floor (as requested)."); |
||||
|
floor_heating_pump_pwm = SC_PUMP_NO_POWER; |
||||
|
is_heating = 0; |
||||
|
} else if (is_heating_enabled && !is_heating && delta_floor_heating > CONFIG_SC_FLOOR_HEATING_DELTA_TEMP_HIGH) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Start heating the floor from the store..."); |
||||
|
floor_heating_pump_pwm = SC_PUMP_HALF_POWER; |
||||
|
is_heating = 1; |
||||
|
} else if (is_heating && delta_floor_heating < CONFIG_SC_FLOOR_HEATING_DELTA_TEMP_LOW) { |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Stop heating the floor from the store..."); |
||||
|
floor_heating_pump_pwm = SC_PUMP_NO_POWER; |
||||
|
is_heating = 0; |
||||
|
} |
||||
|
|
||||
|
ESP_LOGI(SOLAR_LOGGER, "p:%2.1f°C, s.l:%2.1f°C, s.h:%2.1f°C, f.h:%2.1f°C, p.p: %3.0f%%, fh.p: %3.0f%%", readings[panel], readings[store_low], readings[store_high], readings[floor_heating], panel_pump_pwm / 2.55, floor_heating_pump_pwm / 2.55); |
||||
|
|
||||
|
// Set new PWM duty cycle on each pump
|
||||
|
ESP_ERROR_CHECK(ledc_set_duty(LEDC_HIGH_SPEED_MODE, SC_LEDC_CHANNEL_PANEL_PUMP, panel_pump_pwm)); |
||||
|
ESP_ERROR_CHECK(ledc_set_duty(LEDC_HIGH_SPEED_MODE, SC_LEDC_CHANNEL_FLOOR_HEATING_PUMP, floor_heating_pump_pwm)); |
||||
|
ESP_ERROR_CHECK(ledc_update_duty(LEDC_HIGH_SPEED_MODE, SC_LEDC_CHANNEL_PANEL_PUMP)); |
||||
|
ESP_ERROR_CHECK(ledc_update_duty(LEDC_HIGH_SPEED_MODE, SC_LEDC_CHANNEL_FLOOR_HEATING_PUMP)); |
||||
|
|
||||
|
// Only publish data when connected to the MQTT broker and time is synchronized with NTP
|
||||
|
if (IS_READY(MQTT_CONNECTED_BIT|TIME_SYNC_BIT)) { |
||||
|
mqtt_publish_data("solar_panel_temperature", (json_value){MQTT_TYPE_FLOAT, {.f = readings[panel]}}); |
||||
|
mqtt_publish_data("floor_temperature", (json_value){MQTT_TYPE_FLOAT, {.f = readings[floor_heating]}}); |
||||
|
mqtt_publish_data("store_higher_temperature", (json_value){MQTT_TYPE_FLOAT, {.f = readings[store_high]}}); |
||||
|
mqtt_publish_data("store_lower_temperature", (json_value){MQTT_TYPE_FLOAT, {.f = readings[store_low]}}); |
||||
|
mqtt_publish_data("panel_pump_duty_cycle", (json_value){MQTT_TYPE_INT, {.i = panel_pump_pwm}}); |
||||
|
mqtt_publish_data("floor_heating_pump_duty_cycle", (json_value){MQTT_TYPE_INT, {.i = floor_heating_pump_pwm}}); |
||||
|
} |
||||
|
|
||||
|
vTaskDelayUntil(&last_wake_time, (1000 * CONFIG_SC_SAMPLE_PERIOD) / portTICK_PERIOD_MS); |
||||
|
} |
||||
|
vTaskDelete(NULL); |
||||
|
} |
||||
|
|
||||
|
static void solar_pwm_init() { |
||||
|
// Prepare and then apply the LEDC PWM timer configuration
|
||||
|
ledc_timer_config_t ledc_timer_0 = { |
||||
|
.speed_mode = LEDC_HIGH_SPEED_MODE, |
||||
|
.timer_num = LEDC_TIMER_0, |
||||
|
.duty_resolution = LEDC_TIMER_8_BIT, |
||||
|
.freq_hz = CONFIG_SC_PUMP_PWM_FREQ, |
||||
|
.clk_cfg = LEDC_AUTO_CLK |
||||
|
}; |
||||
|
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer_0)); |
||||
|
|
||||
|
// Prepare and then apply the LEDC PWM channel configuration
|
||||
|
ledc_channel_config_t ledc_channel_0 = { |
||||
|
.speed_mode = LEDC_HIGH_SPEED_MODE, |
||||
|
.channel = LEDC_CHANNEL_0, |
||||
|
.timer_sel = LEDC_TIMER_0, |
||||
|
.intr_type = LEDC_INTR_DISABLE, |
||||
|
.gpio_num = CONFIG_SC_PANEL_PUMP_GPIO, |
||||
|
.duty = 0, // Set duty to 0%
|
||||
|
.hpoint = 0 |
||||
|
}; |
||||
|
ledc_channel_config_t ledc_channel_1 = { |
||||
|
.speed_mode = LEDC_HIGH_SPEED_MODE, |
||||
|
.channel = LEDC_CHANNEL_1, |
||||
|
.timer_sel = LEDC_TIMER_0, |
||||
|
.intr_type = LEDC_INTR_DISABLE, |
||||
|
.gpio_num = CONFIG_SC_FLOOR_HEATING_PUMP_GPIO, |
||||
|
.duty = 0, // Set duty to 0%
|
||||
|
.hpoint = 0 |
||||
|
}; |
||||
|
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel_0)); |
||||
|
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel_1)); |
||||
|
} |
||||
|
|
||||
|
static int sensor_index(char * address) { |
||||
|
for (int i = 0; i < SC_EXPECTED_TEMPERATURE_SENSORS_COUNT; i++) { |
||||
|
char rom_code_s[17]; |
||||
|
owb_string_from_rom_code(temperature_sensors[i].rom_code, rom_code_s, sizeof(rom_code_s)); |
||||
|
if (strcmp(address, rom_code_s) == 0) { |
||||
|
return i; |
||||
|
} |
||||
|
} |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
static void solar_ds18b20_init() { |
||||
|
// Stable readings require a brief period before communication
|
||||
|
ESP_LOGI(SOLAR_LOGGER, "Waiting before 1-wire enumeration..."); |
||||
|
vTaskDelay(2000.0 / portTICK_PERIOD_MS); |
||||
|
|
||||
|
// Create a 1-Wire bus, using the RMT timeslot driver
|
||||
|
owb = owb_rmt_initialize(&rmt_driver_info, CONFIG_SC_1WIRE_GPIO, RMT_CHANNEL_1, RMT_CHANNEL_0); |
||||
|
owb_use_crc(owb, true); // enable CRC check for ROM code
|
||||
|
|
||||
|
// Find all connected temperature sensors
|
||||
|
ESP_LOGI(SOLAR_LOGGER, "List of all DS18B20 devices on bus:"); |
||||
|
OneWireBus_ROMCode device_rom_codes[SC_MAX_TEMPERATURE_SENSORS_COUNT] = {0}; |
||||
|
int num_devices = 0; |
||||
|
OneWireBus_SearchState search_state = {0}; |
||||
|
bool found = false; |
||||
|
owb_search_first(owb, &search_state, &found); |
||||
|
|
||||
|
while (found) { |
||||
|
char rom_code_s[17]; |
||||
|
owb_string_from_rom_code(search_state.rom_code, rom_code_s, sizeof(rom_code_s)); |
||||
|
ESP_LOGI(SOLAR_LOGGER, "device %d: %s", num_devices, rom_code_s); |
||||
|
device_rom_codes[num_devices] = search_state.rom_code; |
||||
|
++num_devices; |
||||
|
owb_search_next(owb, &search_state, &found); |
||||
|
} |
||||
|
ESP_LOGI(SOLAR_LOGGER, "Found %d device%s", num_devices, num_devices == 1 ? "" : "s"); |
||||
|
|
||||
|
if (num_devices != SC_EXPECTED_TEMPERATURE_SENSORS_COUNT) { |
||||
|
ESP_LOGE(SOLAR_LOGGER, "Cannot find exactly %d temperature sensors, rebooting!", SC_EXPECTED_TEMPERATURE_SENSORS_COUNT); |
||||
|
vTaskDelay(5000.0 / portTICK_PERIOD_MS); |
||||
|
esp_restart(); |
||||
|
} |
||||
|
|
||||
|
// Initializes all temperature sensors
|
||||
|
for (int i = 0; i < num_devices; ++i) |
||||
|
{ |
||||
|
ds18b20_init(&temperature_sensors[i], owb, device_rom_codes[i]); // associate with bus and device
|
||||
|
ds18b20_use_crc(&temperature_sensors[i], true); // enable CRC check on all reads
|
||||
|
ds18b20_set_resolution(&temperature_sensors[i], DS18B20_RESOLUTION_12_BIT); // use max. resolution
|
||||
|
} |
||||
|
|
||||
|
// Extract sensor addresses from NVS
|
||||
|
nvs_handle_t nvs; |
||||
|
ESP_ERROR_CHECK(nvs_open("solar", NVS_READONLY, &nvs)); |
||||
|
char * panel_sensor_addr = get_nvs_string(nvs, "panel_sensor"); |
||||
|
assert(panel_sensor_addr != NULL); |
||||
|
char * store_higher_sensor_addr = get_nvs_string(nvs, "store_h_sensor"); |
||||
|
assert(store_higher_sensor_addr != NULL); |
||||
|
char * store_lower_sensor_addr = get_nvs_string(nvs, "store_l_sensor"); |
||||
|
assert(store_lower_sensor_addr != NULL); |
||||
|
char * floor_heating_sensor_addr = get_nvs_string(nvs, "fl_ht_sensor"); |
||||
|
assert(floor_heating_sensor_addr != NULL); |
||||
|
|
||||
|
if (panel_sensor_addr == NULL || store_higher_sensor_addr == NULL || store_lower_sensor_addr == NULL || floor_heating_sensor_addr == NULL) { |
||||
|
ESP_LOGE(SOLAR_LOGGER, "Cannot find one of the temperature sensor addresses, check your configuration!"); |
||||
|
vTaskDelay(5000.0 / portTICK_PERIOD_MS); |
||||
|
esp_restart(); |
||||
|
} |
||||
|
|
||||
|
// Match each sensor with its function
|
||||
|
panel = sensor_index(panel_sensor_addr); |
||||
|
assert(panel != -1); |
||||
|
store_high = sensor_index(store_higher_sensor_addr); |
||||
|
assert(store_high != -1); |
||||
|
store_low = sensor_index(store_lower_sensor_addr); |
||||
|
assert(store_low != -1); |
||||
|
floor_heating = sensor_index(floor_heating_sensor_addr); |
||||
|
assert(floor_heating != -1); |
||||
|
|
||||
|
if (panel == -1 || store_high == -1 || store_low == -1 || floor_heating == -1) { |
||||
|
ESP_LOGE(SOLAR_LOGGER, "Cannot find one of the temperature sensors, check your configuration!"); |
||||
|
vTaskDelay(5000.0 / portTICK_PERIOD_MS); |
||||
|
esp_restart(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void solar_init() { |
||||
|
solar_pwm_init(); |
||||
|
solar_ds18b20_init(); |
||||
|
|
||||
|
// Create a task to handle solar monitoring
|
||||
|
BaseType_t xReturned; |
||||
|
xReturned = xTaskCreate(solar_process, |
||||
|
"solar_process", |
||||
|
CONFIG_SC_STACK_SIZE, /* Stack size in words, not bytes. */ |
||||
|
NULL, /* Parameter passed into the task. */ |
||||
|
tskIDLE_PRIORITY + 12, |
||||
|
NULL); |
||||
|
if (xReturned != pdPASS) { |
||||
|
ESP_LOGE(SOLAR_LOGGER, "xTaskCreate('solar_process'): %d", xReturned); |
||||
|
abort(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
#ifndef __SOLAR_H__ |
||||
|
#define __SOLAR_H__ |
||||
|
|
||||
|
void solar_init(); |
||||
|
void solar_set_heating(int enabled); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,61 @@ |
|||||
|
#include <string.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "esp_system.h" |
||||
|
#include "esp_wifi.h" |
||||
|
#include "esp_event.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "nvs_flash.h" |
||||
|
|
||||
|
#include "lwip/err.h" |
||||
|
#include "lwip/sys.h" |
||||
|
|
||||
|
#include "wifi.h" |
||||
|
#include "common.h" |
||||
|
|
||||
|
static const char *WIFI_LOGGER = "wifi"; |
||||
|
|
||||
|
static void wifi_event_handler(void* arg, esp_event_base_t event_base, |
||||
|
int32_t event_id, void* event_data) { |
||||
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { |
||||
|
esp_wifi_connect(); |
||||
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { |
||||
|
ESP_LOGI(WIFI_LOGGER,"Connection to the AP failed!"); |
||||
|
xEventGroupClearBits(services_event_group, WIFI_CONNECTED_BIT); |
||||
|
|
||||
|
ESP_LOGI(WIFI_LOGGER, "Retrying to connect to the AP..."); |
||||
|
esp_wifi_connect(); |
||||
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { |
||||
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; |
||||
|
ESP_LOGI(WIFI_LOGGER, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); |
||||
|
xEventGroupSetBits(services_event_group, WIFI_CONNECTED_BIT); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void wifi_init_sta(void) { |
||||
|
ESP_ERROR_CHECK(esp_netif_init()); |
||||
|
|
||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
||||
|
esp_netif_create_default_wifi_sta(); |
||||
|
|
||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); |
||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
||||
|
|
||||
|
esp_event_handler_instance_t instance_any_id; |
||||
|
esp_event_handler_instance_t instance_got_ip; |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, |
||||
|
ESP_EVENT_ANY_ID, |
||||
|
&wifi_event_handler, |
||||
|
NULL, |
||||
|
&instance_any_id)); |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, |
||||
|
IP_EVENT_STA_GOT_IP, |
||||
|
&wifi_event_handler, |
||||
|
NULL, |
||||
|
&instance_got_ip)); |
||||
|
|
||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); |
||||
|
ESP_ERROR_CHECK(esp_wifi_start()); |
||||
|
|
||||
|
ESP_LOGI(WIFI_LOGGER, "wifi_init_sta finished."); |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
#ifndef __WIFI_H__ |
||||
|
#define __WIFI_H__ |
||||
|
|
||||
|
void wifi_init_sta(void); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,5 @@ |
|||||
|
# contains sensitive data |
||||
|
sdkconfig |
||||
|
sdkconfig.dev |
||||
|
sdkconfig.prod |
||||
|
sdkconfig.defaults |
||||
@ -0,0 +1,6 @@ |
|||||
|
# The following five lines of boilerplate have to be in your project's |
||||
|
# CMakeLists in this exact order for cmake to work correctly |
||||
|
cmake_minimum_required(VERSION 3.5) |
||||
|
|
||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake) |
||||
|
project(provisioner) |
||||
@ -0,0 +1,8 @@ |
|||||
|
#
|
||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
|
# project subdirectory.
|
||||
|
#
|
||||
|
|
||||
|
PROJECT_NAME := provisioner |
||||
|
|
||||
|
include $(IDF_PATH)/make/project.mk |
||||
@ -0,0 +1,2 @@ |
|||||
|
# Settings provisioner |
||||
|
|
||||
@ -0,0 +1,2 @@ |
|||||
|
idf_component_register(SRCS "provision.c" |
||||
|
INCLUDE_DIRS ".") |
||||
@ -0,0 +1,68 @@ |
|||||
|
menu "Provisioning data" |
||||
|
|
||||
|
config ESP_WIFI_SSID |
||||
|
string "WiFi SSID" |
||||
|
default "" |
||||
|
help |
||||
|
SSID (network name) for the example to connect to. |
||||
|
|
||||
|
config ESP_WIFI_PASSWORD |
||||
|
string "WiFi Password" |
||||
|
default "" |
||||
|
help |
||||
|
WiFi password (WPA or WPA2) for the example to use. |
||||
|
|
||||
|
config ESP_MAXIMUM_RETRY |
||||
|
int "Maximum retry" |
||||
|
default 5 |
||||
|
help |
||||
|
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. |
||||
|
|
||||
|
config MQTT_URI |
||||
|
string "MQTT Server URI" |
||||
|
default "mqtts://server:port" |
||||
|
help |
||||
|
MQTT server location. |
||||
|
|
||||
|
config MQTT_USERNAME |
||||
|
string "MQTT username" |
||||
|
default "" |
||||
|
help |
||||
|
MQTT username. |
||||
|
|
||||
|
config MQTT_PASSWORD |
||||
|
string "MQTT password" |
||||
|
default "" |
||||
|
help |
||||
|
MQTT password. |
||||
|
|
||||
|
config FIRMWARE_URL_PATTERN |
||||
|
string "Firmware URL pattern" |
||||
|
default "" |
||||
|
help |
||||
|
Where to download a specific version of the firmware. Complete URL. Must include "%s". |
||||
|
|
||||
|
config PANEL_SENSOR_ADDR |
||||
|
string "1-wire address of the panel sensor" |
||||
|
default "" |
||||
|
help |
||||
|
1-wire address of the panel sensor. |
||||
|
|
||||
|
config STORE_LOWER_SENSOR_ADDR |
||||
|
string "1-wire address of the store lower sensor" |
||||
|
default "" |
||||
|
help |
||||
|
1-wire address of the store lower sensor. |
||||
|
|
||||
|
config STORE_HIGHER_SENSOR_ADDR |
||||
|
string "1-wire address of the store higher sensor" |
||||
|
default "" |
||||
|
help |
||||
|
1-wire address of the store higher sensor. |
||||
|
|
||||
|
config FLOOR_HEATING_SENSOR_ADDR |
||||
|
string "1-wire address of the floor heating sensor" |
||||
|
default "" |
||||
|
help |
||||
|
1-wire address of the floor heating sensor. |
||||
|
endmenu |
||||
@ -0,0 +1,8 @@ |
|||||
|
#
|
||||
|
# Main component makefile.
|
||||
|
#
|
||||
|
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
|
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
|
# in the build directory. This behaviour is entirely configurable,
|
||||
|
# please read the ESP-IDF documents if you need to do this.
|
||||
|
#
|
||||
@ -0,0 +1,169 @@ |
|||||
|
#include <string.h> |
||||
|
#include <stdint.h> |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "freertos/event_groups.h" |
||||
|
#include "esp_system.h" |
||||
|
#include "esp_wifi.h" |
||||
|
#include "esp_event.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "nvs_flash.h" |
||||
|
|
||||
|
#include "lwip/err.h" |
||||
|
#include "lwip/sys.h" |
||||
|
|
||||
|
#include "nvs_flash.h" |
||||
|
#include "nvs.h" |
||||
|
|
||||
|
/* FreeRTOS event group to signal when we are connected*/ |
||||
|
static EventGroupHandle_t s_wifi_event_group; |
||||
|
|
||||
|
/* The event group allows multiple bits for each event, but we only care about two events:
|
||||
|
* - we are connected to the AP with an IP |
||||
|
* - we failed to connect after the maximum amount of retries */ |
||||
|
#define WIFI_CONNECTED_BIT BIT0 |
||||
|
#define WIFI_FAIL_BIT BIT1 |
||||
|
|
||||
|
static const char *TAG = "wifi station"; |
||||
|
|
||||
|
static int s_retry_num = 0; |
||||
|
|
||||
|
static void event_handler(void* arg, esp_event_base_t event_base, |
||||
|
int32_t event_id, void* event_data) |
||||
|
{ |
||||
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { |
||||
|
esp_wifi_connect(); |
||||
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { |
||||
|
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) { |
||||
|
esp_wifi_connect(); |
||||
|
s_retry_num++; |
||||
|
ESP_LOGI(TAG, "retry to connect to the AP"); |
||||
|
} else { |
||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); |
||||
|
} |
||||
|
ESP_LOGI(TAG,"connect to the AP fail"); |
||||
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { |
||||
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; |
||||
|
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); |
||||
|
s_retry_num = 0; |
||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void nvs_dumpall() { |
||||
|
printf("NVS Dump: \n"); |
||||
|
nvs_iterator_t it = nvs_entry_find("nvs", NULL, NVS_TYPE_ANY); |
||||
|
while (it != NULL) { |
||||
|
char * value = NULL; |
||||
|
char namespace[17]; |
||||
|
memset(namespace, 0, 17); |
||||
|
nvs_entry_info_t info; |
||||
|
nvs_entry_info(it, &info); |
||||
|
memcpy(namespace, info.namespace_name, 16); |
||||
|
printf("%s/%s: type 0x%02x, value = %s\n", namespace, info.key, info.type, value ? value : "<UNKNOWN>"); |
||||
|
it = nvs_entry_next(it); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
void wifi_init_sta(void) |
||||
|
{ |
||||
|
s_wifi_event_group = xEventGroupCreate(); |
||||
|
|
||||
|
ESP_ERROR_CHECK(esp_netif_init()); |
||||
|
|
||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
||||
|
esp_netif_create_default_wifi_sta(); |
||||
|
|
||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); |
||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
||||
|
|
||||
|
esp_event_handler_instance_t instance_any_id; |
||||
|
esp_event_handler_instance_t instance_got_ip; |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, |
||||
|
ESP_EVENT_ANY_ID, |
||||
|
&event_handler, |
||||
|
NULL, |
||||
|
&instance_any_id)); |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, |
||||
|
IP_EVENT_STA_GOT_IP, |
||||
|
&event_handler, |
||||
|
NULL, |
||||
|
&instance_got_ip)); |
||||
|
|
||||
|
wifi_config_t wifi_config = { |
||||
|
.sta = { |
||||
|
.ssid = CONFIG_ESP_WIFI_SSID, |
||||
|
.password = CONFIG_ESP_WIFI_PASSWORD, |
||||
|
.threshold.authmode = WIFI_AUTH_WPA2_PSK, |
||||
|
|
||||
|
.pmf_cfg = { |
||||
|
.capable = true, |
||||
|
.required = false |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); |
||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); |
||||
|
ESP_ERROR_CHECK(esp_wifi_start() ); |
||||
|
|
||||
|
ESP_LOGI(TAG, "wifi_init_sta finished."); |
||||
|
|
||||
|
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
|
||||
|
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ |
||||
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, |
||||
|
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, |
||||
|
pdFALSE, |
||||
|
pdFALSE, |
||||
|
portMAX_DELAY); |
||||
|
|
||||
|
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
|
||||
|
* happened. */ |
||||
|
if (bits & WIFI_CONNECTED_BIT) { |
||||
|
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", |
||||
|
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); |
||||
|
} else if (bits & WIFI_FAIL_BIT) { |
||||
|
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", |
||||
|
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); |
||||
|
} else { |
||||
|
ESP_LOGE(TAG, "UNEXPECTED EVENT"); |
||||
|
} |
||||
|
|
||||
|
nvs_handle_t nvs; |
||||
|
ESP_ERROR_CHECK(nvs_open("mqtt", NVS_READWRITE, &nvs)); |
||||
|
nvs_set_str(nvs, "url", CONFIG_MQTT_URI); |
||||
|
nvs_set_str(nvs, "username", CONFIG_MQTT_USERNAME); |
||||
|
nvs_set_str(nvs, "password", CONFIG_MQTT_PASSWORD); |
||||
|
nvs_close(nvs); |
||||
|
|
||||
|
ESP_ERROR_CHECK(nvs_open("ota", NVS_READWRITE, &nvs)); |
||||
|
nvs_set_str(nvs, "update_url", CONFIG_FIRMWARE_URL_PATTERN); |
||||
|
nvs_close(nvs); |
||||
|
|
||||
|
ESP_ERROR_CHECK(nvs_open("solar", NVS_READWRITE, &nvs)); |
||||
|
nvs_set_str(nvs, "panel_sensor", CONFIG_PANEL_SENSOR_ADDR); |
||||
|
nvs_set_str(nvs, "store_h_sensor", CONFIG_STORE_HIGHER_SENSOR_ADDR); |
||||
|
nvs_set_str(nvs, "store_l_sensor", CONFIG_STORE_LOWER_SENSOR_ADDR); |
||||
|
nvs_set_str(nvs, "fl_ht_sensor", CONFIG_FLOOR_HEATING_SENSOR_ADDR); |
||||
|
nvs_close(nvs); |
||||
|
|
||||
|
nvs_dumpall(); |
||||
|
|
||||
|
/* The event will not be processed after unregister */ |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip)); |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); |
||||
|
vEventGroupDelete(s_wifi_event_group); |
||||
|
} |
||||
|
|
||||
|
void app_main(void) |
||||
|
{ |
||||
|
//Initialize NVS
|
||||
|
esp_err_t ret = nvs_flash_init(); |
||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { |
||||
|
ESP_ERROR_CHECK(nvs_flash_erase()); |
||||
|
ret = nvs_flash_init(); |
||||
|
} |
||||
|
ESP_ERROR_CHECK(ret); |
||||
|
|
||||
|
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); |
||||
|
wifi_init_sta(); |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
sdkconfig.dev |
||||
@ -0,0 +1,19 @@ |
|||||
|
CONFIG_MQTT_LWT_TOPIC="test/solar-controller/connected" |
||||
|
CONFIG_MQTT_SOLAR_VALUE_TOPIC="test/solar-controller/status/solar/%s" |
||||
|
CONFIG_MQTT_COMMAND_TOPIC="test/solar-controller/command" |
||||
|
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y |
||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y |
||||
|
CONFIG_PARTITION_TABLE_TWO_OTA=y |
||||
|
CONFIG_LOG_DEFAULT_LEVEL=4 |
||||
|
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y |
||||
|
CONFIG_OTA_ALLOW_HTTP=y |
||||
|
CONFIG_SC_1WIRE_GPIO=4 |
||||
|
CONFIG_SC_SAMPLE_PERIOD=1 |
||||
|
CONFIG_SC_PANEL_PUMP_GPIO=19 |
||||
|
CONFIG_SC_FLOOR_HEATING_PUMP_GPIO=21 |
||||
|
CONFIG_SC_FROST_PROTECTION_TEMP_LOW=16 |
||||
|
CONFIG_SC_FROST_PROTECTION_TEMP_HIGH=18 |
||||
|
CONFIG_SC_PANEL_DELTA_TEMP_LOW=2 |
||||
|
CONFIG_SC_PANEL_DELTA_TEMP_HIGH=3 |
||||
|
CONFIG_SC_FLOOR_HEATING_DELTA_TEMP_LOW=2 |
||||
|
CONFIG_SC_FLOOR_HEATING_DELTA_TEMP_HIGH=3 |
||||
@ -0,0 +1,9 @@ |
|||||
|
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y |
||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y |
||||
|
CONFIG_PARTITION_TABLE_TWO_OTA=y |
||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y |
||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y |
||||
|
# CONFIG_MQTT_TRANSPORT_WEBSOCKET is not set |
||||
|
# CONFIG_LWIP_IPV6 is not set |
||||
|
# CONFIG_ETH_USE_ESP32_EMAC is not set |
||||
|
# CONFIG_ETH_USE_SPI_ETHERNET is not set |
||||
Loading…
Reference in new issue