new release

This commit is contained in:
2025-11-20 07:45:00 +00:00
parent 96b2ab1f57
commit 4820d9111e
106 changed files with 4264 additions and 15581 deletions

View File

@@ -1,14 +1,24 @@
set(srcs
"src/protocols.c"
"src/mqtt.c"
"src/date_time.c"
idf_component_register(
SRCS
"src/protocols.c"
"src/json.c"
"src/mqtt.c"
INCLUDE_DIRS
"include"
PRIV_INCLUDE_DIRS
"src"
PRIV_REQUIRES
nvs_flash
mqtt
cjson
vfs
spiffs
REQUIRES
logger
network
config
evse
peripherals
ocpp
auth
)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "src"
PRIV_REQUIRES nvs_flash esp_http_server esp_netif esp_https_ota app_update json mqtt vfs spiffs
REQUIRES config api logger)

View File

@@ -1,371 +0,0 @@
#!/usr/bin/env python
import sys
ZONES_DIR = "/usr/share/zoneinfo/"
ZONES = [
"Africa/Abidjan",
"Africa/Algiers",
"Africa/Bissau",
"Africa/Cairo",
"Africa/Casablanca",
"Africa/Ceuta",
"Africa/El_Aaiun",
"Africa/Johannesburg",
"Africa/Juba",
"Africa/Khartoum",
"Africa/Lagos",
"Africa/Maputo",
"Africa/Monrovia",
"Africa/Nairobi",
"Africa/Ndjamena",
"Africa/Sao_Tome",
"Africa/Tripoli",
"Africa/Tunis",
"Africa/Windhoek",
"America/Adak",
"America/Anchorage",
"America/Araguaina",
"America/Argentina/Buenos_Aires",
"America/Argentina/Catamarca",
"America/Argentina/Cordoba",
"America/Argentina/Jujuy",
"America/Argentina/La_Rioja",
"America/Argentina/Mendoza",
"America/Argentina/Rio_Gallegos",
"America/Argentina/Salta",
"America/Argentina/San_Juan",
"America/Argentina/San_Luis",
"America/Argentina/Tucuman",
"America/Argentina/Ushuaia",
"America/Asuncion",
"America/Bahia",
"America/Bahia_Banderas",
"America/Barbados",
"America/Belem",
"America/Belize",
"America/Boa_Vista",
"America/Bogota",
"America/Boise",
"America/Cambridge_Bay",
"America/Campo_Grande",
"America/Cancun",
"America/Caracas",
"America/Cayenne",
"America/Cayman",
"America/Chicago",
"America/Chihuahua",
"America/Costa_Rica",
"America/Creston",
"America/Cuiaba",
"America/Curacao",
"America/Danmarkshavn",
"America/Dawson",
"America/Dawson_Creek",
"America/Denver",
"America/Detroit",
"America/Dominica",
"America/Edmonton",
"America/Eirunepe",
"America/El_Salvador",
"America/Fortaleza",
"America/Fort_Nelson",
"America/Glace_Bay",
"America/Godthab",
"America/Goose_Bay",
"America/Grand_Turk",
"America/Grenada",
"America/Guadeloupe",
"America/Guatemala",
"America/Guayaquil",
"America/Guyana",
"America/Halifax",
"America/Havana",
"America/Hermosillo",
"America/Indiana/Indianapolis",
"America/Indiana/Knox",
"America/Indiana/Marengo",
"America/Indiana/Petersburg",
"America/Indiana/Tell_City",
"America/Indiana/Vevay",
"America/Indiana/Vincennes",
"America/Indiana/Winamac",
"America/Inuvik",
"America/Iqaluit",
"America/Jamaica",
"America/Juneau",
"America/Kentucky/Louisville",
"America/Kentucky/Monticello",
"America/La_Paz",
"America/Lima",
"America/Los_Angeles",
"America/Maceio",
"America/Managua",
"America/Manaus",
"America/Marigot",
"America/Martinique",
"America/Matamoros",
"America/Mazatlan",
"America/Menominee",
"America/Merida",
"America/Metlakatla",
"America/Mexico_City",
"America/Miquelon",
"America/Moncton",
"America/Monterrey",
"America/Montevideo",
"America/New_York",
"America/Nome",
"America/Noronha",
"America/North_Dakota/Beulah",
"America/North_Dakota/Center",
"America/North_Dakota/New_Salem",
"America/Nuuk",
"America/Ojinaga",
"America/Panama",
"America/Paramaribo",
"America/Phoenix",
"America/Port-au-Prince",
"America/Porto_Velho",
"America/Puerto_Rico",
"America/Punta_Arenas",
"America/Rankin_Inlet",
"America/Recife",
"America/Regina",
"America/Resolute",
"America/Rio_Branco",
"America/Santarem",
"America/Santiago",
"America/Santo_Domingo",
"America/Sao_Paulo",
"America/Scoresbysund",
"America/Sitka",
"America/St_Johns",
"America/Swift_Current",
"America/Tegucigalpa",
"America/Thule",
"America/Tijuana",
"America/Toronto",
"America/Vancouver",
"America/Whitehorse",
"America/Winnipeg",
"America/Yakutat",
"Antarctica/Casey",
"Antarctica/Davis",
"Antarctica/Macquarie",
"Antarctica/Mawson",
"Antarctica/Palmer",
"Antarctica/Rothera",
"Antarctica/Troll",
"Asia/Almaty",
"Asia/Amman",
"Asia/Anadyr",
"Asia/Aqtau",
"Asia/Aqtobe",
"Asia/Ashgabat",
"Asia/Atyrau",
"Asia/Baghdad",
"Asia/Bahrain",
"Asia/Baku",
"Asia/Bangkok",
"Asia/Barnaul",
"Asia/Beirut",
"Asia/Bishkek",
"Asia/Brunei",
"Asia/Chita",
"Asia/Choibalsan",
"Asia/Colombo",
"Asia/Damascus",
"Asia/Dhaka",
"Asia/Dili",
"Asia/Dubai",
"Asia/Dushanbe",
"Asia/Famagusta",
"Asia/Gaza",
"Asia/Hebron",
"Asia/Ho_Chi_Minh",
"Asia/Hong_Kong",
"Asia/Hovd",
"Asia/Irkutsk",
"Asia/Jakarta",
"Asia/Jayapura",
"Asia/Jerusalem",
"Asia/Kabul",
"Asia/Kamchatka",
"Asia/Karachi",
"Asia/Kathmandu",
"Asia/Khandyga",
"Asia/Kolkata",
"Asia/Krasnoyarsk",
"Asia/Kuala_Lumpur",
"Asia/Kuching",
"Asia/Kuwait",
"Asia/Macau",
"Asia/Magadan",
"Asia/Makassar",
"Asia/Manila",
"Asia/Nicosia",
"Asia/Novokuznetsk",
"Asia/Novosibirsk",
"Asia/Omsk",
"Asia/Oral",
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
"Asia/Qyzylorda",
"Asia/Riyadh",
"Asia/Sakhalin",
"Asia/Samarkand",
"Asia/Seoul",
"Asia/Shanghai",
"Asia/Singapore",
"Asia/Srednekolymsk",
"Asia/Taipei",
"Asia/Tashkent",
"Asia/Tbilisi",
"Asia/Tehran",
"Asia/Thimphu",
"Asia/Tokyo",
"Asia/Tomsk",
"Asia/Ulaanbaatar",
"Asia/Urumqi",
"Asia/Ust-Nera",
"Asia/Vientiane",
"Asia/Vladivostok",
"Asia/Yakutsk",
"Asia/Yangon",
"Asia/Yekaterinburg",
"Asia/Yerevan",
"Atlantic/Azores",
"Atlantic/Bermuda",
"Atlantic/Canary",
"Atlantic/Cape_Verde",
"Atlantic/Faroe",
"Atlantic/Madeira",
"Atlantic/South_Georgia",
"Atlantic/Stanley",
"Australia/Adelaide",
"Australia/Brisbane",
"Australia/Broken_Hill",
"Australia/Darwin",
"Australia/Eucla",
"Australia/Hobart",
"Australia/Lindeman",
"Australia/Lord_Howe",
"Australia/Melbourne",
"Australia/Perth",
"Australia/Sydney",
"Europe/Andorra",
"Europe/Astrakhan",
"Europe/Athens",
"Europe/Belgrade",
"Europe/Berlin",
"Europe/Brussels",
"Europe/Bucharest",
"Europe/Budapest",
"Europe/Chisinau",
"Europe/Dublin",
"Europe/Gibraltar",
"Europe/Helsinki",
"Europe/Istanbul",
"Europe/Kaliningrad",
"Europe/Kyiv",
"Europe/Kirov",
"Europe/Lisbon",
"Europe/London",
"Europe/Madrid",
"Europe/Malta",
"Europe/Minsk",
"Europe/Moscow",
"Europe/Paris",
"Europe/Prague",
"Europe/Riga",
"Europe/Rome",
"Europe/Samara",
"Europe/Saratov",
"Europe/Simferopol",
"Europe/Sofia",
"Europe/Tallinn",
"Europe/Tirane",
"Europe/Ulyanovsk",
"Europe/Vienna",
"Europe/Vilnius",
"Europe/Volgograd",
"Europe/Warsaw",
"Europe/Zurich",
"Indian/Chagos",
"Indian/Maldives",
"Indian/Mauritius",
"Pacific/Apia",
"Pacific/Auckland",
"Pacific/Bougainville",
"Pacific/Chatham",
"Pacific/Chuuk",
"Pacific/Easter",
"Pacific/Efate",
"Pacific/Enderbury",
"Pacific/Fakaofo",
"Pacific/Fiji",
"Pacific/Funafuti",
"Pacific/Galapagos",
"Pacific/Gambier",
"Pacific/Guadalcanal",
"Pacific/Guam",
"Pacific/Honolulu",
"Pacific/Kiritimati",
"Pacific/Kosrae",
"Pacific/Kwajalein",
"Pacific/Majuro",
"Pacific/Marquesas",
"Pacific/Midway",
"Pacific/Nauru",
"Pacific/Niue",
"Pacific/Norfolk",
"Pacific/Noumea",
"Pacific/Pago_Pago",
"Pacific/Palau",
"Pacific/Pitcairn",
"Pacific/Port_Moresby",
"Pacific/Rarotonga",
"Pacific/Tahiti",
"Pacific/Tarawa",
"Pacific/Tongatapu",
"Etc/GMT",
"Etc/GMT-1",
"Etc/GMT-2",
"Etc/GMT-3",
"Etc/GMT-4",
"Etc/GMT-5",
"Etc/GMT-6",
"Etc/GMT-7",
"Etc/GMT-8",
"Etc/GMT-9",
"Etc/GMT-10",
"Etc/GMT-11",
"Etc/GMT-12",
"Etc/GMT-13",
"Etc/GMT-14",
"Etc/GMT+1",
"Etc/GMT+2",
"Etc/GMT+3",
"Etc/GMT+4",
"Etc/GMT+5",
"Etc/GMT+6",
"Etc/GMT+7",
"Etc/GMT+8",
"Etc/GMT+9",
"Etc/GMT+10",
"Etc/GMT+11",
"Etc/GMT+12",
"Etc/UTC"
]
def get_tz_string(timezone):
data = open(ZONES_DIR + timezone, "rb").read().split(b"\n")[-2]
return data.decode("utf-8")
if __name__ == "__main__":
f = open("./src/tz_data.h", "w")
for timezone in ZONES:
f.write('\t{{"{}", "{}"}},\n'.format(timezone, get_tz_string(timezone)))
f.close()

View File

@@ -1,61 +0,0 @@
#ifndef DATE_TIME_H
#define DATE_TIME_H
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Initialize timezone and NTP
*
*/
void date_time_init(void);
/**
* @brief Return true if NTP is enabled, stored in NVS
*
* @return true
* @return false
*/
bool date_time_is_ntp_enabled(void);
/**
* @brief Get NTP server, string length 64, stored in NVS
*
* @param value
*/
void date_time_get_ntp_server(char* value);
/**
* @brief Return true if NTP server from DHCP fetch is enabled, stored in NVS
*
* @return true
* @return false
*/
bool date_time_is_ntp_from_dhcp(void);
/**
* @brief Set timezone and NTP config
*
* @param enabled
* @param server
* @param from_dhcp
* @return esp_err_t
*/
esp_err_t date_time_set_ntp_config(bool enabled, const char* server, bool from_dhcp);
/**
* @brief Get timezone, string length 64, stored in NVS
*
* @param value
*/
void date_time_get_timezone(char* value);
/**
* @brief Set timezone, string length 64, stored in NVS
*
* @param value
*/
esp_err_t date_time_set_timezone(const char* value);
#endif /* DATE_TIME_H */

View File

@@ -0,0 +1,38 @@
#ifndef JSON_H_
#define JSON_H_
#include <stdbool.h>
#include "esp_err.h"
#include "cJSON.h"
/**
* @brief Gera um objeto JSON com a configuração atual do EVSE.
*
* Contém parâmetros como corrente máxima, limites de tempo,
* trava do conector, temperatura e configuração do OCPP.
*
* @return Ponteiro para cJSON (deve ser liberado com cJSON_Delete()).
*/
cJSON* json_get_evse_config(void);
/**
* @brief Define a configuração do EVSE a partir de um objeto JSON.
*
* Aplica valores recebidos de protocolos como MQTT ou REST.
*
* @param root Objeto JSON com os campos válidos.
* @return ESP_OK se todos os parâmetros foram aplicados com sucesso.
*/
esp_err_t json_set_evse_config(cJSON* root);
/**
* @brief Retorna o estado atual do EVSE em formato JSON.
*
* Inclui estado de operação, erros, limites, sessão atual e medições elétricas.
*
* @return Ponteiro para cJSON (deve ser liberado com cJSON_Delete()).
*/
cJSON* json_get_state(void);
#endif /* JSON_H_ */

View File

@@ -1,27 +0,0 @@
#ifndef MODBUS_TCP_H
#define MODBUS_TCP_H
#include <stdbool.h>
/**
* @brief Init modbus tcp
*
*/
void modbus_tcp_init(void);
/**
* @brief Set enabled, stored in NVS
*
* @param enabled
*/
void modbus_tcp_set_enabled(bool enabled);
/**
* @brief Get enabled, stored in NVS
*
* @return true
* @return false
*/
bool modbus_tcp_is_enabled(void);
#endif /* MODBUS_TCP_H */

View File

@@ -6,63 +6,108 @@
#include "esp_err.h"
/**
* @brief Initializes MQTT client and starts background task if enabled in NVS
* @file mqtt.h
* @brief MQTT configuration and control interface.
*
* This module provides initialization, configuration,
* and runtime access functions for the MQTT client.
*
* Configuration is persisted in NVS under namespace "mqtt".
*/
/* -------------------------------------------------------------------------- */
/* Definitions */
/* -------------------------------------------------------------------------- */
#define MQTT_MAX_SERVER_LEN 64 /**< Max length for MQTT server URI */
#define MQTT_MAX_USER_LEN 32 /**< Max length for MQTT username */
#define MQTT_MAX_PASSWORD_LEN 64 /**< Max length for MQTT password */
#define MQTT_MAX_BASE_TOPIC_LEN 64 /**< Max length for MQTT base topic */
/* -------------------------------------------------------------------------- */
/* Public Functions */
/* -------------------------------------------------------------------------- */
/**
* @brief Initialize MQTT subsystem.
*
* Loads configuration from NVS and starts background publish task
* if MQTT is enabled. Must be called once during system startup.
*/
void mqtt_init(void);
/**
* @brief Set MQTT config
*
* @param enabled
* @param server NULL value will be skiped
* @param base_topic NULL value will be skiped
* @param user NULL value will be skiped
* @param password NULL value will be skiped
* @param periodicity 0 value will be skiped
* @return esp_err_t
* @brief Restart the MQTT client safely.
*
* Stops the current MQTT client (if running) and starts a new one
* with the configuration currently stored in NVS.
*
* Useful when changing Wi-Fi networks, credentials, or broker settings.
*
* @return ESP_OK on success, or an ESP_ERR_* code otherwise.
*/
esp_err_t mqtt_set_config(bool enabled, const char* server, const char* base_topic, const char* user, const char* password, uint16_t periodicity);
esp_err_t mqtt_restart(void);
/**
* @brief Get MQTT enabled, stored in NVS
*
* @return true
* @return false
* @brief Set and persist MQTT configuration parameters in NVS.
*
* Any NULL parameter will be skipped (the previous value remains stored).
*
* @param enabled Whether MQTT should be enabled (true/false).
* @param server Broker URI (e.g. "mqtt://192.168.1.10").
* @param base_topic Base topic prefix for publish/subscribe.
* @param user MQTT username (optional).
* @param password MQTT password (optional).
* @param periodicity Publish interval (in seconds). Must be >0 when enabled.
*
* @return ESP_OK on success, or an ESP_ERR_* code otherwise.
*/
esp_err_t mqtt_set_config(bool enabled,
const char *server,
const char *base_topic,
const char *user,
const char *password,
uint16_t periodicity);
/**
* @brief Get whether MQTT is enabled.
*
* @return true if enabled, false otherwise.
*/
bool mqtt_get_enabled(void);
/**
* @brief Get MQTT server, string length 64, stored in NVS
*
* @param value
* @brief Get MQTT broker URI stored in NVS.
*
* @param[out] value Buffer to receive the URI (min length: MQTT_MAX_SERVER_LEN).
*/
void mqtt_get_server(char* value);
void mqtt_get_server(char *value);
/**
* @brief Get MQTT password, string length 64, stored in NVS
*
* @param value
* @brief Get MQTT base topic stored in NVS.
*
* @param[out] value Buffer to receive the base topic (min length: MQTT_MAX_BASE_TOPIC_LEN).
*/
void mqtt_get_password(char* value);
void mqtt_get_base_topic(char *value);
/**
* @brief Get MQTT base topic, string length 32, stored in NVS
*
* @param value
* @brief Get MQTT username stored in NVS.
*
* @param[out] value Buffer to receive the username (min length: MQTT_MAX_USER_LEN).
*/
void mqtt_get_base_topic(char* value);
void mqtt_get_user(char *value);
/**
* @brief Get MQTT user, string length 32, stored in NVS
*
* @param value
* @brief Get MQTT password stored in NVS.
*
* @param[out] value Buffer to receive the password (min length: MQTT_MAX_PASSWORD_LEN).
*/
void mqtt_get_user(char* value);
void mqtt_get_password(char *value);
/**
* @brief Get MQTT periodicity in second, stored in NVS
*
* @return uint16_t
* @brief Get MQTT publish periodicity in seconds.
*
* @return Publish interval in seconds (default: 30).
*/
uint16_t mqtt_get_periodicity(void);

View File

@@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

View File

@@ -1,136 +0,0 @@
#include <time.h>
#include "esp_log.h"
#include "esp_sntp.h"
#include "esp_netif_sntp.h"
#include "nvs.h"
#include "date_time.h"
#define NVS_NAMESPACE "date_time"
#define NVS_NTP_ENABLED "ntp_en"
#define NVS_NTP_SERVER "ntp_server"
#define NVS_NTP_FROM_DHCP "ntp_from_dhcp"
#define NVS_TIMEZONE "timezone"
static const char* TAG = "date_time";
static nvs_handle nvs;
static char ntp_server[64]; // if renew_servers_after_new_IP = false, will be used static string reference
static const char* tz_data[][2] = {
#include "tz_data.h"
{NULL, NULL}
};
static const char* find_tz(const char* name)
{
if (name != NULL) {
int index = 0;
while (true) {
if (tz_data[index][0] == NULL) {
return NULL;
}
if (strcmp(tz_data[index][0], name) == 0) {
return tz_data[index][1];
}
index++;
}
}
return NULL;
}
void date_time_init(void)
{
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
if (date_time_is_ntp_enabled()) {
date_time_get_ntp_server(ntp_server);
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(ntp_server);
esp_err_t ret = esp_netif_sntp_init(&config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SNTP init return %s", esp_err_to_name(ret));
}
}
char str[64];
date_time_get_timezone(str);
const char *tz = find_tz(str);
if (tz) {
setenv("TZ", tz, 1);
tzset();
} else {
ESP_LOGW(TAG, "Unknown timezone %s", str);
}
}
bool date_time_is_ntp_enabled(void)
{
uint8_t value = false;
nvs_get_u8(nvs, NVS_NTP_ENABLED, &value);
return value;
}
void date_time_get_ntp_server(char* value)
{
size_t len = 64;
value[0] = '\0';
nvs_get_str(nvs, NVS_NTP_SERVER, value, &len);
}
bool date_time_is_ntp_from_dhcp(void)
{
uint8_t value = false;
nvs_get_u8(nvs, NVS_NTP_FROM_DHCP, &value);
return value;
}
esp_err_t date_time_set_ntp_config(bool enabled, const char* server, bool from_dhcp)
{
esp_err_t ret = ESP_OK;
esp_netif_sntp_deinit();
if (enabled) {
strcpy(ntp_server, server);
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(ntp_server);
config.renew_servers_after_new_IP = from_dhcp;
ret = esp_netif_sntp_init(&config);
}
if (ret == ESP_OK) {
nvs_set_u8(nvs, NVS_NTP_ENABLED, enabled);
nvs_set_str(nvs, NVS_NTP_SERVER, server);
nvs_set_u8(nvs, NVS_NTP_FROM_DHCP, from_dhcp);
}
return ret;
}
void date_time_get_timezone(char* value)
{
size_t len = 64;
value[0] = '\0';
strcpy(value, "Etc/UTC");
nvs_get_str(nvs, NVS_TIMEZONE, value, &len);
}
esp_err_t date_time_set_timezone(const char* value)
{
const char* tz = find_tz(value);
if (tz) {
setenv("TZ", tz, 1);
tzset();
nvs_set_str(nvs, NVS_TIMEZONE, value);
return ESP_OK;
} else {
ESP_LOGW(TAG, "Unknown timezone %s", value);
return ESP_ERR_INVALID_ARG;
}
}

204
components/protocols/src/json.c Executable file
View File

@@ -0,0 +1,204 @@
// === Início de: components/protocols/src/json.c ===
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "esp_wifi.h"
#include "esp_timer.h"
#include "esp_chip_info.h"
#include "esp_mac.h"
#include "esp_log.h"
#include "json.h"
#include "mqtt.h"
#include "network.h"
#include "evse_error.h"
#include "evse_api.h"
#include "auth.h"
#include "evse_limits.h"
#include "evse_state.h"
#include "evse_config.h"
#include "ocpp.h"
#include "board_config.h"
#include "socket_lock.h"
#include "proximity.h"
#include "temp_sensor.h"
#include "evse_meter.h"
static const char *TAG = "json";
//
// ===== EVSE CONFIG JSON =====
//
cJSON *json_get_evse_config(void)
{
cJSON *root = cJSON_CreateObject();
if (!root)
return NULL;
cJSON_AddNumberToObject(root, "maxChargingCurrent", evse_get_max_charging_current());
cJSON_AddNumberToObject(root, "chargingCurrent", evse_get_charging_current());
cJSON_AddNumberToObject(root, "defaultChargingCurrent", evse_get_default_charging_current());
cJSON_AddBoolToObject(root, "requireAuth", auth_get_mode());
cJSON_AddBoolToObject(root, "socketOutlet", evse_get_socket_outlet());
cJSON_AddBoolToObject(root, "rcm", evse_is_rcm());
cJSON_AddNumberToObject(root, "temperatureThreshold", evse_get_temp_threshold());
cJSON_AddNumberToObject(root, "consumptionLimit", evse_get_consumption_limit());
cJSON_AddNumberToObject(root, "defaultConsumptionLimit", evse_get_default_consumption_limit());
cJSON_AddNumberToObject(root, "chargingTimeLimit", evse_get_charging_time_limit());
cJSON_AddNumberToObject(root, "defaultChargingTimeLimit", evse_get_default_charging_time_limit());
cJSON_AddNumberToObject(root, "underPowerLimit", evse_get_under_power_limit());
cJSON_AddNumberToObject(root, "defaultUnderPowerLimit", evse_get_default_under_power_limit());
cJSON_AddNumberToObject(root, "socketLockOperatingTime", socket_lock_get_operating_time());
cJSON_AddNumberToObject(root, "socketLockBreakTime", socket_lock_get_break_time());
cJSON_AddBoolToObject(root, "socketLockDetectionHigh", socket_lock_is_detection_high());
cJSON_AddNumberToObject(root, "socketLockRetryCount", socket_lock_get_retry_count());
char str[64];
cJSON_AddBoolToObject(root, "enabledocpp", ocpp_get_enabled());
ocpp_get_server(str);
cJSON_AddStringToObject(root, "serverocpp", str);
return root;
}
//
// ===== SET EVSE CONFIG (from MQTT or REST) =====
//
esp_err_t json_set_evse_config(cJSON *root)
{
if (!root)
return ESP_ERR_INVALID_ARG;
// Alguns setters retornam esp_err_t, outros void. Para manter compatibilidade,
// chamamos sem propagar erro (se existir, será tratado internamente).
#define SET_NUM(key, fn) \
do \
{ \
const cJSON *item = cJSON_GetObjectItem(root, key); \
if (cJSON_IsNumber(item)) \
{ \
fn(item->valuedouble); \
} \
} while (0)
#define SET_BOOL(key, fn) \
do \
{ \
const cJSON *item = cJSON_GetObjectItem(root, key); \
if (cJSON_IsBool(item)) \
{ \
fn(cJSON_IsTrue(item)); \
} \
} while (0)
SET_NUM("maxChargingCurrent", evse_set_max_charging_current);
SET_NUM("chargingCurrent", evse_set_charging_current);
SET_NUM("defaultChargingCurrent", evse_set_default_charging_current);
SET_BOOL("socketOutlet", evse_set_socket_outlet);
SET_BOOL("rcm", evse_set_rcm);
SET_NUM("temperatureThreshold", evse_set_temp_threshold);
SET_NUM("consumptionLimit", evse_set_consumption_limit);
SET_NUM("defaultConsumptionLimit", evse_set_default_consumption_limit);
SET_NUM("chargingTimeLimit", evse_set_charging_time_limit);
SET_NUM("defaultChargingTimeLimit", evse_set_default_charging_time_limit);
SET_NUM("underPowerLimit", evse_set_under_power_limit);
SET_NUM("defaultUnderPowerLimit", evse_set_default_under_power_limit);
SET_NUM("socketLockOperatingTime", socket_lock_set_operating_time);
SET_NUM("socketLockBreakTime", socket_lock_set_break_time);
const cJSON *retry = cJSON_GetObjectItem(root, "socketLockRetryCount");
if (cJSON_IsNumber(retry))
socket_lock_set_retry_count(retry->valueint);
const cJSON *detect = cJSON_GetObjectItem(root, "socketLockDetectionHigh");
if (cJSON_IsBool(detect))
socket_lock_set_detection_high(cJSON_IsTrue(detect));
const cJSON *ocpp_enabled = cJSON_GetObjectItem(root, "enabledocpp");
if (cJSON_IsBool(ocpp_enabled))
ocpp_set_enabled(cJSON_IsTrue(ocpp_enabled));
const cJSON *ocpp_server = cJSON_GetObjectItem(root, "serverocpp");
if (cJSON_IsString(ocpp_server))
ocpp_set_server(cJSON_GetStringValue(ocpp_server));
ESP_LOGI(TAG, "EVSE configuration updated successfully");
return ESP_OK;
}
//
// ===== EVSE STATE JSON =====
//
cJSON *json_get_state(void)
{
cJSON *root = cJSON_CreateObject();
if (!root)
return NULL;
cJSON_AddStringToObject(root, "state", evse_state_to_str(evse_get_state()));
cJSON_AddBoolToObject(root, "available", evse_config_is_available());
cJSON_AddBoolToObject(root, "enabled", evse_config_is_enabled());
cJSON_AddBoolToObject(root, "pendingAuth", auth_get_mode());
cJSON_AddBoolToObject(root, "limitReached", evse_is_limit_reached());
// Add error list
uint32_t error = evse_error_get_bits();
if (error == 0)
{
cJSON_AddNullToObject(root, "errors");
}
else
{
cJSON *errors = cJSON_CreateArray();
if (error & EVSE_ERR_PILOT_FAULT_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("pilot_fault"));
if (error & EVSE_ERR_DIODE_SHORT_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("diode_short"));
if (error & EVSE_ERR_LOCK_FAULT_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("lock_fault"));
if (error & EVSE_ERR_UNLOCK_FAULT_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("unlock_fault"));
if (error & EVSE_ERR_RCM_TRIGGERED_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("rcm_triggered"));
if (error & EVSE_ERR_RCM_SELFTEST_FAULT_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("rcm_selftest_fault"));
if (error & EVSE_ERR_TEMPERATURE_HIGH_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("temperature_high"));
if (error & EVSE_ERR_TEMPERATURE_FAULT_BIT)
cJSON_AddItemToArray(errors, cJSON_CreateString("temperature_fault"));
cJSON_AddItemToObject(root, "errors", errors);
}
// Session info
evse_session_t sess;
if (evse_get_session(&sess))
{
cJSON_AddNumberToObject(root, "sessionTime", (double)sess.start_tick);
cJSON_AddNumberToObject(root, "chargingTime", (double)sess.duration_s);
cJSON_AddNumberToObject(root, "consumption", (double)sess.energy_wh);
}
else
{
cJSON_AddNullToObject(root, "sessionTime");
cJSON_AddNumberToObject(root, "chargingTime", 0);
cJSON_AddNumberToObject(root, "consumption", 0);
}
// Meter readings
float voltage[EVSE_METER_PHASE_COUNT];
float current[EVSE_METER_PHASE_COUNT];
int power[EVSE_METER_PHASE_COUNT];
evse_meter_get_voltage(voltage);
evse_meter_get_current(current);
evse_meter_get_power(power);
cJSON_AddItemToObject(root, "power", cJSON_CreateIntArray(power, EVSE_METER_PHASE_COUNT));
cJSON_AddItemToObject(root, "voltage", cJSON_CreateFloatArray(voltage, EVSE_METER_PHASE_COUNT));
cJSON_AddItemToObject(root, "current", cJSON_CreateFloatArray(current, EVSE_METER_PHASE_COUNT));
return root;
}
// === Fim de: components/protocols/src/json.c ===

View File

@@ -1,304 +1,437 @@
// === Início de: components/protocols/src/mqtt.c ===
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_event.h"
#include "mqtt_client.h"
#include "nvs.h"
#include "mqtt.h"
#include "json.h"
#include "board_config.h"
#include "timeout_utils.h"
#include "mqtt_client.h"
#define NVS_NAMESPACE "mqtt"
#define NVS_ENABLED "enabled"
#define NVS_SERVER "server"
#define NVS_BASE_TOPIC "base_topic"
#define NVS_USER "user"
#define NVS_PASSWORD "password"
#define NVS_PERIODICITY "periodicity"
#define NVS_NAMESPACE "mqtt"
#define NVS_ENABLED "enabled"
#define NVS_SERVER "server"
#define NVS_BASE_TOPIC "base_topic"
#define NVS_USER "user"
#define NVS_PASSWORD "password"
#define NVS_PERIODICITY "periodicity"
static const char *TAG = "mqtt";
static const char* TAG = "mqtt";
static TaskHandle_t client_task = NULL;
static esp_mqtt_client_handle_t client = NULL;
static uint16_t periodicity = 30;
static SemaphoreHandle_t mqtt_mutex = NULL;
static uint16_t periodicity = 30; // seconds
// Nem todas as versões do IDF têm esp_mqtt_client_is_connected(); usamos um flag.
static volatile bool mqtt_connected = false;
static esp_err_t open_mqtt_nvs(nvs_handle_t *handle) {
static esp_err_t open_mqtt_nvs(nvs_handle_t *handle)
{
return nvs_open(NVS_NAMESPACE, NVS_READWRITE, handle);
}
static void subcribe_topics(void)
//
// Helper: safely publish JSON message
//
static void publish_message(const char *topic_suffix, cJSON *root)
{
ESP_LOGI(TAG, "[MQTT] Subscribing to topics");
if (!root) return;
char base[32];
mqtt_get_base_topic(base);
if (xSemaphoreTake(mqtt_mutex, pdMS_TO_TICKS(500)) == pdTRUE)
{
if (client && mqtt_connected)
{
char base[MQTT_MAX_BASE_TOPIC_LEN] = {0};
mqtt_get_base_topic(base);
char topic[64];
char topic[128];
snprintf(topic, sizeof(topic), "%s%s", base, topic_suffix);
snprintf(topic, sizeof(topic), "%s/request/#", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, " subscribed: %s", topic);
snprintf(topic, sizeof(topic), "%s/set/config/#", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, " subscribed: %s", topic);
snprintf(topic, sizeof(topic), "%s/enable", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, " subscribed: %s", topic);
}
static void publish_message(const char* topic, cJSON* root)
{
char target_topic[64];
mqtt_get_base_topic(target_topic);
strncat(target_topic, topic, sizeof(target_topic) - strlen(target_topic) - 1);
const char* json = cJSON_PrintUnformatted(root);
esp_mqtt_client_publish(client, target_topic, json, 0, 1, 0);
free((void*)json);
}
static void handle_message(const char* topic, const char* data)
{
char base_topic[32];
mqtt_get_base_topic(base_topic);
ESP_LOGI(TAG, "Topic: %s", topic);
ESP_LOGI(TAG, "data: %s", data);
ESP_LOGI(TAG, "base_topic: %s", base_topic);
if (strncmp(topic, base_topic, strlen(base_topic)) == 0) {
const char* sub_topic = &topic[strlen(base_topic)];
ESP_LOGI(TAG, "Sub_topic: %s", sub_topic);
if (strcmp(sub_topic, "/request/config/evse") == 0) {
cJSON* root = json_get_evse_config();
publish_message("/response/config/evse", root);
cJSON_Delete(root);
} else if (strcmp(sub_topic, "/request/config/wifi") == 0) {
//cJSON* root = json_get_wifi_config();
//publish_message("/response/config/wifi", root);
//cJSON_Delete(root);
} else if (strcmp(sub_topic, "/request/config/mqtt") == 0) {
cJSON* root = json_get_mqtt_config();
publish_message("/response/config/mqtt", root);
cJSON_Delete(root);
} else if (strcmp(sub_topic, "/request/boardConfig") == 0) {
cJSON* root = json_get_board_config();
publish_message("/response/boardConfig", root);
cJSON_Delete(root);
} else if (strcmp(sub_topic, "/request/info") == 0) {
cJSON* root = json_get_info();
publish_message("/response/info", root);
cJSON_Delete(root);
} else if (strcmp(sub_topic, "/request/restart") == 0) {
timeout_restart();
} else if (strcmp(sub_topic, "/set/config/evse") == 0) {
cJSON* root = cJSON_Parse(data);
json_set_evse_config(root);
cJSON_Delete(root);
} else if (strcmp(sub_topic, "/set/config/wifi") == 0) {
//cJSON* root = cJSON_Parse(data);
//json_set_wifi_config(root, true);
//cJSON_Delete(root);
} else if (strcmp(sub_topic, "/set/config/mqtt") == 0) {
cJSON* root = cJSON_Parse(data);
json_set_mqtt_config(root);
cJSON_Delete(root);
}
char *json = cJSON_PrintUnformatted(root);
if (json)
{
esp_mqtt_client_publish(client, topic, json, 0, 1, 0);
ESP_LOGI(TAG, "Published to %s", topic);
free(json);
}
}
else
{
ESP_LOGW(TAG, "MQTT client not connected — skipping publish");
}
xSemaphoreGive(mqtt_mutex);
}
else
{
ESP_LOGW(TAG, "MQTT mutex timeout during publish");
}
}
static void event_handler(void* handler_args, esp_event_base_t base, int32_t event_id, void* event_data)
//
// Subscriptions
//
static void subscribe_topics(void)
{
if (!client) return;
char base[MQTT_MAX_BASE_TOPIC_LEN] = {0};
mqtt_get_base_topic(base);
const char *subs[] = {
"/request/#",
"/set/config/#",
"/enable",
"/request/restart",
"/request/config/evse",
"/request/boardConfig"
};
for (size_t i = 0; i < sizeof(subs) / sizeof(subs[0]); i++)
{
char topic[MQTT_MAX_BASE_TOPIC_LEN + 32];
snprintf(topic, sizeof(topic), "%s%s", base, subs[i]);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "[MQTT] Subscribed: %s", topic);
}
}
//
// Message handler
//
static void handle_message(const char *topic, const char *data)
{
if (!topic || !data) return;
char base[MQTT_MAX_BASE_TOPIC_LEN] = {0};
mqtt_get_base_topic(base);
if (strncmp(topic, base, strlen(base)) != 0) return;
const char *sub_topic = &topic[strlen(base)];
ESP_LOGI(TAG, "[MQTT] Received on %s: %s", sub_topic, data);
if (strcmp(sub_topic, "/request/config/evse") == 0)
{
cJSON *root = json_get_evse_config();
publish_message("/response/config/evse", root);
cJSON_Delete(root);
}
else if (strcmp(sub_topic, "/set/config/evse") == 0)
{
cJSON *root = cJSON_Parse(data);
if (!root)
{
ESP_LOGE(TAG, "Invalid JSON payload on topic %s", topic);
return;
}
json_set_evse_config(root);
cJSON_Delete(root);
}
else if (strcmp(sub_topic, "/request/restart") == 0)
{
ESP_LOGW(TAG, "Restart request received (TODO: add auth check)");
// esp_restart();
}
}
//
// MQTT event handler
//
static void event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_mqtt_event_handle_t event = event_data;
switch (event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "[MQTT] Connected to broker");
if (client_task) vTaskResume(client_task);
subcribe_topics();
break;
switch (event_id)
{
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "[MQTT] Connected to broker");
mqtt_connected = true;
if (client_task) vTaskResume(client_task);
subscribe_topics();
break;
case MQTT_EVENT_DATA: {
char topic[64] = {0};
char data[256] = {0};
case MQTT_EVENT_DATA:
{
char topic[128] = {0};
char data_buf[512] = {0};
int tlen = MIN(event->topic_len, sizeof(topic) - 1);
int dlen = MIN(event->data_len, sizeof(data) - 1);
int tlen = MIN(event->topic_len, (int)sizeof(topic) - 1);
int dlen = MIN(event->data_len, (int)sizeof(data_buf) - 1);
memcpy(topic, event->topic, tlen);
memcpy(data, event->data, dlen);
memcpy(topic, event->topic, tlen);
memcpy(data_buf, event->data, dlen);
handle_message(topic, data);
break;
}
default:
break;
handle_message(topic, data_buf);
break;
}
case MQTT_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "[MQTT] Disconnected from broker");
mqtt_connected = false;
break;
default:
break;
}
}
static void client_task_func(void* param)
//
// Background periodic publisher
//
static void client_task_func(void *param)
{
while (true) {
if (!client) vTaskSuspend(NULL);
cJSON* root = json_get_state();
publish_message("/state", root);
cJSON_Delete(root);
for (;;)
{
if (client && mqtt_connected)
{
cJSON *root = json_get_state();
publish_message("/state", root);
cJSON_Delete(root);
}
else
{
ESP_LOGW(TAG, "[MQTT] Not connected — skipping state publish");
}
vTaskDelay(pdMS_TO_TICKS(periodicity * 1000));
}
}
//
// Start/stop MQTT
//
static void client_start(void)
{
char server[64], user[32], password[64];
char server[MQTT_MAX_SERVER_LEN] = {0};
char user[MQTT_MAX_USER_LEN] = {0};
char password[MQTT_MAX_PASSWORD_LEN] = {0};
mqtt_get_server(server);
mqtt_get_user(user);
mqtt_get_password(password);
if (!strlen(server))
{
ESP_LOGW(TAG, "[MQTT] No server configured");
return;
}
esp_mqtt_client_config_t cfg = {
.broker.address.uri = server,
.credentials.username = user,
.credentials.authentication.password = password
};
if (!client) {
if (!client)
{
client = esp_mqtt_client_init(&cfg);
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, event_handler, client);
esp_mqtt_client_start(client);
ESP_LOGI(TAG, "[MQTT] Client started");
}
}
static void client_stop(void)
{
if (client) {
if (client)
{
esp_mqtt_client_stop(client);
esp_mqtt_client_destroy(client);
client = NULL;
mqtt_connected = false;
ESP_LOGI(TAG, "[MQTT] Client stopped");
}
}
esp_err_t mqtt_restart(void)
{
ESP_LOGI(TAG, "[MQTT] Restarting client...");
if (client)
{
esp_mqtt_client_stop(client);
esp_mqtt_client_destroy(client);
client = NULL;
mqtt_connected = false;
ESP_LOGI(TAG, "[MQTT] Existing client stopped");
}
vTaskDelay(pdMS_TO_TICKS(500));
client_start();
if (client)
{
ESP_LOGI(TAG, "[MQTT] Restart complete");
return ESP_OK;
}
ESP_LOGE(TAG, "[MQTT] Restart failed — no valid configuration");
return ESP_FAIL;
}
//
// Public API
//
void mqtt_init(void)
{
if (!mqtt_mutex)
mqtt_mutex = xSemaphoreCreateMutex();
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK) {
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_u16(handle, NVS_PERIODICITY, &periodicity);
nvs_close(handle);
if (periodicity == 0) periodicity = 30;
}
esp_register_shutdown_handler(&client_stop);
xTaskCreate(client_task_func, "mqtt_client_task", 3 * 1024, NULL, 5, &client_task);
xTaskCreate(client_task_func, "mqtt_client_task", 4 * 1024, NULL, 5, &client_task);
if (mqtt_get_enabled()) {
if (mqtt_get_enabled())
{
client_start();
}
}
esp_err_t mqtt_set_config(bool enabled, const char* server, const char* base_topic, const char* user, const char* password, uint16_t _periodicity)
esp_err_t mqtt_set_config(bool enabled, const char *server, const char *base_topic,
const char *user, const char *password, uint16_t _periodicity)
{
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) != ESP_OK) return ESP_ERR_INVALID_STATE;
if (open_mqtt_nvs(&handle) != ESP_OK)
return ESP_ERR_INVALID_STATE;
char full_server[64];
if (server && strncmp(server, "mqtt://", 7) != 0 && strncmp(server, "tcp://", 6) != 0) {
char full_server[MQTT_MAX_SERVER_LEN];
if (server && strncmp(server, "mqtt://", 7) != 0 && strncmp(server, "tcp://", 6) != 0)
{
snprintf(full_server, sizeof(full_server), "mqtt://%s", server);
server = full_server;
}
if (enabled) {
if (!server || !*server) return ESP_ERR_INVALID_ARG;
if (!base_topic || !*base_topic) return ESP_ERR_INVALID_ARG;
if (_periodicity == 0) return ESP_ERR_INVALID_ARG;
if (enabled)
{
if (!server || !*server || !base_topic || !*base_topic || !_periodicity)
{
nvs_close(handle);
return ESP_ERR_INVALID_ARG;
}
}
if (server) nvs_set_str(handle, NVS_SERVER, server);
if (server) nvs_set_str(handle, NVS_SERVER, server);
if (base_topic) nvs_set_str(handle, NVS_BASE_TOPIC, base_topic);
if (user) nvs_set_str(handle, NVS_USER, user);
if (password) nvs_set_str(handle, NVS_PASSWORD, password);
nvs_set_u8(handle, NVS_ENABLED, enabled);
nvs_set_u16(handle, NVS_PERIODICITY, _periodicity);
if (user) nvs_set_str(handle, NVS_USER, user);
if (password) nvs_set_str(handle, NVS_PASSWORD, password);
periodicity = _periodicity;
nvs_set_u8(handle, NVS_ENABLED, enabled ? 1 : 0);
nvs_set_u16(handle, NVS_PERIODICITY, _periodicity);
periodicity = _periodicity ? _periodicity : periodicity;
esp_err_t err = nvs_commit(handle);
nvs_close(handle);
if (err != ESP_OK) return err;
if (err != ESP_OK)
return err;
if (enabled) {
if (enabled)
client_start();
} else {
else
client_stop();
}
return ESP_OK;
}
/* ---------------------- Getters públicos (faltavam) ---------------------- */
bool mqtt_get_enabled(void)
{
nvs_handle_t handle;
uint8_t val = false;
if (open_mqtt_nvs(&handle) == ESP_OK) {
nvs_get_u8(handle, NVS_ENABLED, &val);
uint8_t en = 0;
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_u8(handle, NVS_ENABLED, &en);
nvs_close(handle);
}
return val;
return en != 0;
}
void mqtt_get_server(char* value)
static void nvs_get_str_into(nvs_handle_t handle, const char *key, char *out, size_t outlen)
{
if (!value) return;
value[0] = '\0';
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK) {
size_t len = 64;
nvs_get_str(handle, NVS_SERVER, value, &len);
nvs_close(handle);
}
if (!out || outlen == 0) return;
out[0] = '\0';
size_t len = outlen;
esp_err_t err = nvs_get_str(handle, key, out, &len);
if (err != ESP_OK) out[0] = '\0';
}
void mqtt_get_base_topic(char* value)
void mqtt_get_server(char *value)
{
if (!value) return;
value[0] = '\0';
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK) {
size_t len = 32;
nvs_get_str(handle, NVS_BASE_TOPIC, value, &len);
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_str_into(handle, NVS_SERVER, value, MQTT_MAX_SERVER_LEN);
nvs_close(handle);
}
else if (value) value[0] = '\0';
}
void mqtt_get_user(char* value)
void mqtt_get_base_topic(char *value)
{
if (!value) return;
value[0] = '\0';
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK) {
size_t len = 32;
nvs_get_str(handle, NVS_USER, value, &len);
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_str_into(handle, NVS_BASE_TOPIC, value, MQTT_MAX_BASE_TOPIC_LEN);
nvs_close(handle);
}
else if (value) value[0] = '\0';
}
void mqtt_get_password(char* value)
void mqtt_get_user(char *value)
{
if (!value) return;
value[0] = '\0';
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK) {
size_t len = 64;
nvs_get_str(handle, NVS_PASSWORD, value, &len);
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_str_into(handle, NVS_USER, value, MQTT_MAX_USER_LEN);
nvs_close(handle);
}
else if (value) value[0] = '\0';
}
void mqtt_get_password(char *value)
{
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_str_into(handle, NVS_PASSWORD, value, MQTT_MAX_PASSWORD_LEN);
nvs_close(handle);
}
else if (value) value[0] = '\0';
}
uint16_t mqtt_get_periodicity(void)
{
// devolve o cache atual; se não tiver sido carregado, lê NVS
if (periodicity == 0)
{
nvs_handle_t handle;
if (open_mqtt_nvs(&handle) == ESP_OK)
{
nvs_get_u16(handle, NVS_PERIODICITY, &periodicity);
nvs_close(handle);
if (periodicity == 0) periodicity = 30;
}
else
{
periodicity = 30;
}
}
return periodicity;
}
}
// === Fim de: components/protocols/src/mqtt.c ===

View File

@@ -1,14 +1,7 @@
#include "protocols.h"
#include "date_time.h"
//#include "rest.h"
#include "mqtt.h"
//#include "modbus_tcp.h"
void protocols_init(void)
{
date_time_init();
/* Serve static files from the SPIFFS data partition */
// rest_init("/data");
mqtt_init();
//modbus_tcp_init();
}

View File

@@ -1,354 +0,0 @@
{"Africa/Abidjan", "GMT0"},
{"Africa/Algiers", "CET-1"},
{"Africa/Bissau", "GMT0"},
{"Africa/Cairo", "EET-2EEST,M4.5.5/0,M10.5.4/24"},
{"Africa/Casablanca", "<+01>-1"},
{"Africa/Ceuta", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Africa/El_Aaiun", "<+01>-1"},
{"Africa/Johannesburg", "SAST-2"},
{"Africa/Juba", "CAT-2"},
{"Africa/Khartoum", "CAT-2"},
{"Africa/Lagos", "WAT-1"},
{"Africa/Maputo", "CAT-2"},
{"Africa/Monrovia", "GMT0"},
{"Africa/Nairobi", "EAT-3"},
{"Africa/Ndjamena", "WAT-1"},
{"Africa/Sao_Tome", "GMT0"},
{"Africa/Tripoli", "EET-2"},
{"Africa/Tunis", "CET-1"},
{"Africa/Windhoek", "CAT-2"},
{"America/Adak", "HST10HDT,M3.2.0,M11.1.0"},
{"America/Anchorage", "AKST9AKDT,M3.2.0,M11.1.0"},
{"America/Araguaina", "<-03>3"},
{"America/Argentina/Buenos_Aires", "<-03>3"},
{"America/Argentina/Catamarca", "<-03>3"},
{"America/Argentina/Cordoba", "<-03>3"},
{"America/Argentina/Jujuy", "<-03>3"},
{"America/Argentina/La_Rioja", "<-03>3"},
{"America/Argentina/Mendoza", "<-03>3"},
{"America/Argentina/Rio_Gallegos", "<-03>3"},
{"America/Argentina/Salta", "<-03>3"},
{"America/Argentina/San_Juan", "<-03>3"},
{"America/Argentina/San_Luis", "<-03>3"},
{"America/Argentina/Tucuman", "<-03>3"},
{"America/Argentina/Ushuaia", "<-03>3"},
{"America/Asuncion", "<-04>4<-03>,M10.1.0/0,M3.4.0/0"},
{"America/Bahia", "<-03>3"},
{"America/Bahia_Banderas", "CST6"},
{"America/Barbados", "AST4"},
{"America/Belem", "<-03>3"},
{"America/Belize", "CST6"},
{"America/Boa_Vista", "<-04>4"},
{"America/Bogota", "<-05>5"},
{"America/Boise", "MST7MDT,M3.2.0,M11.1.0"},
{"America/Cambridge_Bay", "MST7MDT,M3.2.0,M11.1.0"},
{"America/Campo_Grande", "<-04>4"},
{"America/Cancun", "EST5"},
{"America/Caracas", "<-04>4"},
{"America/Cayenne", "<-03>3"},
{"America/Cayman", "EST5"},
{"America/Chicago", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Chihuahua", "CST6"},
{"America/Costa_Rica", "CST6"},
{"America/Creston", "MST7"},
{"America/Cuiaba", "<-04>4"},
{"America/Curacao", "AST4"},
{"America/Danmarkshavn", "GMT0"},
{"America/Dawson", "MST7"},
{"America/Dawson_Creek", "MST7"},
{"America/Denver", "MST7MDT,M3.2.0,M11.1.0"},
{"America/Detroit", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Dominica", "AST4"},
{"America/Edmonton", "MST7MDT,M3.2.0,M11.1.0"},
{"America/Eirunepe", "<-05>5"},
{"America/El_Salvador", "CST6"},
{"America/Fortaleza", "<-03>3"},
{"America/Fort_Nelson", "MST7"},
{"America/Glace_Bay", "AST4ADT,M3.2.0,M11.1.0"},
{"America/Godthab", "<-02>2<-01>,M3.5.0/-1,M10.5.0/0"},
{"America/Goose_Bay", "AST4ADT,M3.2.0,M11.1.0"},
{"America/Grand_Turk", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Grenada", "AST4"},
{"America/Guadeloupe", "AST4"},
{"America/Guatemala", "CST6"},
{"America/Guayaquil", "<-05>5"},
{"America/Guyana", "<-04>4"},
{"America/Halifax", "AST4ADT,M3.2.0,M11.1.0"},
{"America/Havana", "CST5CDT,M3.2.0/0,M11.1.0/1"},
{"America/Hermosillo", "MST7"},
{"America/Indiana/Indianapolis", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Indiana/Knox", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Indiana/Marengo", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Indiana/Petersburg", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Indiana/Tell_City", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Indiana/Vevay", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Indiana/Vincennes", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Indiana/Winamac", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Inuvik", "MST7MDT,M3.2.0,M11.1.0"},
{"America/Iqaluit", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Jamaica", "EST5"},
{"America/Juneau", "AKST9AKDT,M3.2.0,M11.1.0"},
{"America/Kentucky/Louisville", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Kentucky/Monticello", "EST5EDT,M3.2.0,M11.1.0"},
{"America/La_Paz", "<-04>4"},
{"America/Lima", "<-05>5"},
{"America/Los_Angeles", "PST8PDT,M3.2.0,M11.1.0"},
{"America/Maceio", "<-03>3"},
{"America/Managua", "CST6"},
{"America/Manaus", "<-04>4"},
{"America/Marigot", "AST4"},
{"America/Martinique", "AST4"},
{"America/Matamoros", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Mazatlan", "MST7"},
{"America/Menominee", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Merida", "CST6"},
{"America/Metlakatla", "AKST9AKDT,M3.2.0,M11.1.0"},
{"America/Mexico_City", "CST6"},
{"America/Miquelon", "<-03>3<-02>,M3.2.0,M11.1.0"},
{"America/Moncton", "AST4ADT,M3.2.0,M11.1.0"},
{"America/Monterrey", "CST6"},
{"America/Montevideo", "<-03>3"},
{"America/New_York", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Nome", "AKST9AKDT,M3.2.0,M11.1.0"},
{"America/Noronha", "<-02>2"},
{"America/North_Dakota/Beulah", "CST6CDT,M3.2.0,M11.1.0"},
{"America/North_Dakota/Center", "CST6CDT,M3.2.0,M11.1.0"},
{"America/North_Dakota/New_Salem", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Nuuk", "<-02>2<-01>,M3.5.0/-1,M10.5.0/0"},
{"America/Ojinaga", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Panama", "EST5"},
{"America/Paramaribo", "<-03>3"},
{"America/Phoenix", "MST7"},
{"America/Port-au-Prince", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Porto_Velho", "<-04>4"},
{"America/Puerto_Rico", "AST4"},
{"America/Punta_Arenas", "<-03>3"},
{"America/Rankin_Inlet", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Recife", "<-03>3"},
{"America/Regina", "CST6"},
{"America/Resolute", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Rio_Branco", "<-05>5"},
{"America/Santarem", "<-03>3"},
{"America/Santiago", "<-04>4<-03>,M9.1.6/24,M4.1.6/24"},
{"America/Santo_Domingo", "AST4"},
{"America/Sao_Paulo", "<-03>3"},
{"America/Scoresbysund", "<-01>1<+00>,M3.5.0/0,M10.5.0/1"},
{"America/Sitka", "AKST9AKDT,M3.2.0,M11.1.0"},
{"America/St_Johns", "NST3:30NDT,M3.2.0,M11.1.0"},
{"America/Swift_Current", "CST6"},
{"America/Tegucigalpa", "CST6"},
{"America/Thule", "AST4ADT,M3.2.0,M11.1.0"},
{"America/Tijuana", "PST8PDT,M3.2.0,M11.1.0"},
{"America/Toronto", "EST5EDT,M3.2.0,M11.1.0"},
{"America/Vancouver", "PST8PDT,M3.2.0,M11.1.0"},
{"America/Whitehorse", "MST7"},
{"America/Winnipeg", "CST6CDT,M3.2.0,M11.1.0"},
{"America/Yakutat", "AKST9AKDT,M3.2.0,M11.1.0"},
{"Antarctica/Casey", "<+11>-11"},
{"Antarctica/Davis", "<+07>-7"},
{"Antarctica/Macquarie", "AEST-10AEDT,M10.1.0,M4.1.0/3"},
{"Antarctica/Mawson", "<+05>-5"},
{"Antarctica/Palmer", "<-03>3"},
{"Antarctica/Rothera", "<-03>3"},
{"Antarctica/Troll", "<+00>0<+02>-2,M3.5.0/1,M10.5.0/3"},
{"Asia/Almaty", "<+06>-6"},
{"Asia/Amman", "<+03>-3"},
{"Asia/Anadyr", "<+12>-12"},
{"Asia/Aqtau", "<+05>-5"},
{"Asia/Aqtobe", "<+05>-5"},
{"Asia/Ashgabat", "<+05>-5"},
{"Asia/Atyrau", "<+05>-5"},
{"Asia/Baghdad", "<+03>-3"},
{"Asia/Bahrain", "<+03>-3"},
{"Asia/Baku", "<+04>-4"},
{"Asia/Bangkok", "<+07>-7"},
{"Asia/Barnaul", "<+07>-7"},
{"Asia/Beirut", "EET-2EEST,M3.5.0/0,M10.5.0/0"},
{"Asia/Bishkek", "<+06>-6"},
{"Asia/Brunei", "<+08>-8"},
{"Asia/Chita", "<+09>-9"},
{"Asia/Choibalsan", "<+08>-8"},
{"Asia/Colombo", "<+0530>-5:30"},
{"Asia/Damascus", "<+03>-3"},
{"Asia/Dhaka", "<+06>-6"},
{"Asia/Dili", "<+09>-9"},
{"Asia/Dubai", "<+04>-4"},
{"Asia/Dushanbe", "<+05>-5"},
{"Asia/Famagusta", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Asia/Gaza", "EET-2EEST,M3.4.4/50,M10.4.4/50"},
{"Asia/Hebron", "EET-2EEST,M3.4.4/50,M10.4.4/50"},
{"Asia/Ho_Chi_Minh", "<+07>-7"},
{"Asia/Hong_Kong", "HKT-8"},
{"Asia/Hovd", "<+07>-7"},
{"Asia/Irkutsk", "<+08>-8"},
{"Asia/Jakarta", "WIB-7"},
{"Asia/Jayapura", "WIT-9"},
{"Asia/Jerusalem", "IST-2IDT,M3.4.4/26,M10.5.0"},
{"Asia/Kabul", "<+0430>-4:30"},
{"Asia/Kamchatka", "<+12>-12"},
{"Asia/Karachi", "PKT-5"},
{"Asia/Kathmandu", "<+0545>-5:45"},
{"Asia/Khandyga", "<+09>-9"},
{"Asia/Kolkata", "IST-5:30"},
{"Asia/Krasnoyarsk", "<+07>-7"},
{"Asia/Kuala_Lumpur", "<+08>-8"},
{"Asia/Kuching", "<+08>-8"},
{"Asia/Kuwait", "<+03>-3"},
{"Asia/Macau", "CST-8"},
{"Asia/Magadan", "<+11>-11"},
{"Asia/Makassar", "WITA-8"},
{"Asia/Manila", "PST-8"},
{"Asia/Nicosia", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Asia/Novokuznetsk", "<+07>-7"},
{"Asia/Novosibirsk", "<+07>-7"},
{"Asia/Omsk", "<+06>-6"},
{"Asia/Oral", "<+05>-5"},
{"Asia/Pontianak", "WIB-7"},
{"Asia/Pyongyang", "KST-9"},
{"Asia/Qatar", "<+03>-3"},
{"Asia/Qyzylorda", "<+05>-5"},
{"Asia/Riyadh", "<+03>-3"},
{"Asia/Sakhalin", "<+11>-11"},
{"Asia/Samarkand", "<+05>-5"},
{"Asia/Seoul", "KST-9"},
{"Asia/Shanghai", "CST-8"},
{"Asia/Singapore", "<+08>-8"},
{"Asia/Srednekolymsk", "<+11>-11"},
{"Asia/Taipei", "CST-8"},
{"Asia/Tashkent", "<+05>-5"},
{"Asia/Tbilisi", "<+04>-4"},
{"Asia/Tehran", "<+0330>-3:30"},
{"Asia/Thimphu", "<+06>-6"},
{"Asia/Tokyo", "JST-9"},
{"Asia/Tomsk", "<+07>-7"},
{"Asia/Ulaanbaatar", "<+08>-8"},
{"Asia/Urumqi", "<+06>-6"},
{"Asia/Ust-Nera", "<+10>-10"},
{"Asia/Vientiane", "<+07>-7"},
{"Asia/Vladivostok", "<+10>-10"},
{"Asia/Yakutsk", "<+09>-9"},
{"Asia/Yangon", "<+0630>-6:30"},
{"Asia/Yekaterinburg", "<+05>-5"},
{"Asia/Yerevan", "<+04>-4"},
{"Atlantic/Azores", "<-01>1<+00>,M3.5.0/0,M10.5.0/1"},
{"Atlantic/Bermuda", "AST4ADT,M3.2.0,M11.1.0"},
{"Atlantic/Canary", "WET0WEST,M3.5.0/1,M10.5.0"},
{"Atlantic/Cape_Verde", "<-01>1"},
{"Atlantic/Faroe", "WET0WEST,M3.5.0/1,M10.5.0"},
{"Atlantic/Madeira", "WET0WEST,M3.5.0/1,M10.5.0"},
{"Atlantic/South_Georgia", "<-02>2"},
{"Atlantic/Stanley", "<-03>3"},
{"Australia/Adelaide", "ACST-9:30ACDT,M10.1.0,M4.1.0/3"},
{"Australia/Brisbane", "AEST-10"},
{"Australia/Broken_Hill", "ACST-9:30ACDT,M10.1.0,M4.1.0/3"},
{"Australia/Darwin", "ACST-9:30"},
{"Australia/Eucla", "<+0845>-8:45"},
{"Australia/Hobart", "AEST-10AEDT,M10.1.0,M4.1.0/3"},
{"Australia/Lindeman", "AEST-10"},
{"Australia/Lord_Howe", "<+1030>-10:30<+11>-11,M10.1.0,M4.1.0"},
{"Australia/Melbourne", "AEST-10AEDT,M10.1.0,M4.1.0/3"},
{"Australia/Perth", "AWST-8"},
{"Australia/Sydney", "AEST-10AEDT,M10.1.0,M4.1.0/3"},
{"Europe/Andorra", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Astrakhan", "<+04>-4"},
{"Europe/Athens", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Belgrade", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Berlin", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Brussels", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Bucharest", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Budapest", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Chisinau", "EET-2EEST,M3.5.0,M10.5.0/3"},
{"Europe/Dublin", "IST-1GMT0,M10.5.0,M3.5.0/1"},
{"Europe/Gibraltar", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Helsinki", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Istanbul", "<+03>-3"},
{"Europe/Kaliningrad", "EET-2"},
{"Europe/Kyiv", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Kirov", "MSK-3"},
{"Europe/Lisbon", "WET0WEST,M3.5.0/1,M10.5.0"},
{"Europe/London", "GMT0BST,M3.5.0/1,M10.5.0"},
{"Europe/Madrid", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Malta", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Minsk", "<+03>-3"},
{"Europe/Moscow", "MSK-3"},
{"Europe/Paris", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Prague", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Riga", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Rome", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Samara", "<+04>-4"},
{"Europe/Saratov", "<+04>-4"},
{"Europe/Simferopol", "MSK-3"},
{"Europe/Sofia", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Tallinn", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Tirane", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Ulyanovsk", "<+04>-4"},
{"Europe/Vienna", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Vilnius", "EET-2EEST,M3.5.0/3,M10.5.0/4"},
{"Europe/Volgograd", "MSK-3"},
{"Europe/Warsaw", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Europe/Zurich", "CET-1CEST,M3.5.0,M10.5.0/3"},
{"Indian/Chagos", "<+06>-6"},
{"Indian/Maldives", "<+05>-5"},
{"Indian/Mauritius", "<+04>-4"},
{"Pacific/Apia", "<+13>-13"},
{"Pacific/Auckland", "NZST-12NZDT,M9.5.0,M4.1.0/3"},
{"Pacific/Bougainville", "<+11>-11"},
{"Pacific/Chatham", "<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45"},
{"Pacific/Chuuk", "<+10>-10"},
{"Pacific/Easter", "<-06>6<-05>,M9.1.6/22,M4.1.6/22"},
{"Pacific/Efate", "<+11>-11"},
{"Pacific/Enderbury", "<+13>-13"},
{"Pacific/Fakaofo", "<+13>-13"},
{"Pacific/Fiji", "<+12>-12"},
{"Pacific/Funafuti", "<+12>-12"},
{"Pacific/Galapagos", "<-06>6"},
{"Pacific/Gambier", "<-09>9"},
{"Pacific/Guadalcanal", "<+11>-11"},
{"Pacific/Guam", "ChST-10"},
{"Pacific/Honolulu", "HST10"},
{"Pacific/Kiritimati", "<+14>-14"},
{"Pacific/Kosrae", "<+11>-11"},
{"Pacific/Kwajalein", "<+12>-12"},
{"Pacific/Majuro", "<+12>-12"},
{"Pacific/Marquesas", "<-0930>9:30"},
{"Pacific/Midway", "SST11"},
{"Pacific/Nauru", "<+12>-12"},
{"Pacific/Niue", "<-11>11"},
{"Pacific/Norfolk", "<+11>-11<+12>,M10.1.0,M4.1.0/3"},
{"Pacific/Noumea", "<+11>-11"},
{"Pacific/Pago_Pago", "SST11"},
{"Pacific/Palau", "<+09>-9"},
{"Pacific/Pitcairn", "<-08>8"},
{"Pacific/Port_Moresby", "<+10>-10"},
{"Pacific/Rarotonga", "<-10>10"},
{"Pacific/Tahiti", "<-10>10"},
{"Pacific/Tarawa", "<+12>-12"},
{"Pacific/Tongatapu", "<+13>-13"},
{"Etc/GMT", "GMT0"},
{"Etc/GMT-1", "<+01>-1"},
{"Etc/GMT-2", "<+02>-2"},
{"Etc/GMT-3", "<+03>-3"},
{"Etc/GMT-4", "<+04>-4"},
{"Etc/GMT-5", "<+05>-5"},
{"Etc/GMT-6", "<+06>-6"},
{"Etc/GMT-7", "<+07>-7"},
{"Etc/GMT-8", "<+08>-8"},
{"Etc/GMT-9", "<+09>-9"},
{"Etc/GMT-10", "<+10>-10"},
{"Etc/GMT-11", "<+11>-11"},
{"Etc/GMT-12", "<+12>-12"},
{"Etc/GMT-13", "<+13>-13"},
{"Etc/GMT-14", "<+14>-14"},
{"Etc/GMT+1", "<-01>1"},
{"Etc/GMT+2", "<-02>2"},
{"Etc/GMT+3", "<-03>3"},
{"Etc/GMT+4", "<-04>4"},
{"Etc/GMT+5", "<-05>5"},
{"Etc/GMT+6", "<-06>6"},
{"Etc/GMT+7", "<-07>7"},
{"Etc/GMT+8", "<-08>8"},
{"Etc/GMT+9", "<-09>9"},
{"Etc/GMT+10", "<-10>10"},
{"Etc/GMT+11", "<-11>11"},
{"Etc/GMT+12", "<-12>12"},
{"Etc/UTC", "UTC0"},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,23 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> -->
<!-- Remover link para tailwind.min.css -->
<!-- <link href="/tailwind.min.css" rel="stylesheet"> -->
<style>
body {
font-family: 'Arial', 'Helvetica', 'sans-serif'; /* Usando fontes genéricas do sistema */
}
</style>
<title>Vite + React</title>
<script type="module" crossorigin src="/assets/index-C_08vMAY.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Doq3307m.css">
</head>
<body>
<div id="root"></div>
<!-- Adicionar o link para o seu arquivo CSS com o Tailwind configurado -->
</body>
</html>

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB