mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-27 20:56:35 +00:00
commit
63f14adbf6
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,6 +9,8 @@
|
|||||||
.clang_complete
|
.clang_complete
|
||||||
.gcc-flags.json
|
.gcc-flags.json
|
||||||
.cache
|
.cache
|
||||||
|
data
|
||||||
|
unpacked_fs
|
||||||
tasmota/user_config_override.h
|
tasmota/user_config_override.h
|
||||||
build
|
build
|
||||||
build_output
|
build_output
|
||||||
|
11
API.md
11
API.md
@ -14,8 +14,8 @@ Callback Id | Bool | xdrv | xsns | xnrg | xlgt | Description
|
|||||||
----------------------------|------|------|------|------|------|----------------------------------
|
----------------------------|------|------|------|------|------|----------------------------------
|
||||||
FUNC_SETTINGS_OVERRIDE | | x | | | | Override start-up settings
|
FUNC_SETTINGS_OVERRIDE | | x | | | | Override start-up settings
|
||||||
FUNC_PIN_STATE | x | 1 | 2 | | | At GPIO configuration
|
FUNC_PIN_STATE | x | 1 | 2 | | | At GPIO configuration
|
||||||
FUNC_MODULE_INIT | x | 1 | | | 2 | Init module specific parameters
|
FUNC_MODULE_INIT | x | 3 | 1 | | 2 | Init module specific parameters
|
||||||
FUNC_PRE_INIT | | 1 | | 2 | | Once GPIO have been established
|
FUNC_PRE_INIT | | 1 | 3 | 2 | | Once GPIO have been established
|
||||||
FUNC_INIT | | 1 | 3 | 2 | | At end of initialisation
|
FUNC_INIT | | 1 | 3 | 2 | | At end of initialisation
|
||||||
FUNC_LOOP | | 1 | 2 | | | In main loop
|
FUNC_LOOP | | 1 | 2 | | | In main loop
|
||||||
FUNC_EVERY_50_MSECOND | | 1 | 2 | | |
|
FUNC_EVERY_50_MSECOND | | 1 | 2 | | |
|
||||||
@ -34,7 +34,7 @@ FUNC_COMMAND_SENSOR | x | | x | | | When command Se
|
|||||||
FUNC_MQTT_SUBSCRIBE | | x | | | | At end of MQTT subscriptions
|
FUNC_MQTT_SUBSCRIBE | | x | | | | At end of MQTT subscriptions
|
||||||
FUNC_MQTT_INIT | | x | | | | Once at end of MQTT connection
|
FUNC_MQTT_INIT | | x | | | | Once at end of MQTT connection
|
||||||
FUNC_MQTT_DATA | x | x | | | | Before decoding command
|
FUNC_MQTT_DATA | x | x | | | | Before decoding command
|
||||||
FUNC_SET_POWER | | x | | | | Before setting relays
|
FUNC_SET_POWER | | 1 | 2 | | | Before setting relays
|
||||||
FUNC_SET_DEVICE_POWER | x | x | | | | Set relay
|
FUNC_SET_DEVICE_POWER | x | x | | | | Set relay
|
||||||
FUNC_SHOW_SENSOR | | x | | | | When FUNC_JSON_APPEND completes
|
FUNC_SHOW_SENSOR | | x | | | | When FUNC_JSON_APPEND completes
|
||||||
FUNC_ANY_KEY | | x | | | |
|
FUNC_ANY_KEY | | x | | | |
|
||||||
@ -49,6 +49,8 @@ FUNC_WEB_ADD_MAIN_BUTTON | | 1 | 2 | | | Add a main butt
|
|||||||
FUNC_WEB_ADD_HANDLER | | 1 | 2 | | | Add a webserver handler
|
FUNC_WEB_ADD_HANDLER | | 1 | 2 | | | Add a webserver handler
|
||||||
FUNC_SET_CHANNELS | | 2 | | | 1 |
|
FUNC_SET_CHANNELS | | 2 | | | 1 |
|
||||||
FUNC_SET_SCHEME | | | | | x |
|
FUNC_SET_SCHEME | | | | | x |
|
||||||
|
FUNC_HOTPLUG_SCAN | | | x | | |
|
||||||
|
FUNC_DEVICE_GROUP_ITEM | | x | | | |
|
||||||
|
|
||||||
The numbers represent the sequence of execution
|
The numbers represent the sequence of execution
|
||||||
|
|
||||||
@ -89,12 +91,15 @@ CFG: Loaded from flash at FB, Count 1581
|
|||||||
xdrv - FUNC_SETTINGS_OVERRIDE
|
xdrv - FUNC_SETTINGS_OVERRIDE
|
||||||
xdrv - FUNC_PIN_STATE
|
xdrv - FUNC_PIN_STATE
|
||||||
xsns - FUNC_PIN_STATE
|
xsns - FUNC_PIN_STATE
|
||||||
|
xsns - FUNC_MODULE_INIT
|
||||||
xdrv - FUNC_MODULE_INIT
|
xdrv - FUNC_MODULE_INIT
|
||||||
xlgt - FUNC_MODULE_INIT
|
xlgt - FUNC_MODULE_INIT
|
||||||
xdrv - FUNC_PRE_INIT
|
xdrv - FUNC_PRE_INIT
|
||||||
xnrg - FUNC_PRE_INIT
|
xnrg - FUNC_PRE_INIT
|
||||||
|
xsns - FUNC_PRE_INIT
|
||||||
SRC: Restart
|
SRC: Restart
|
||||||
xdrv - FUNC_SET_POWER
|
xdrv - FUNC_SET_POWER
|
||||||
|
xsns - FUNC_SET_POWER
|
||||||
xlgt - FUNC_SET_CHANNELS
|
xlgt - FUNC_SET_CHANNELS
|
||||||
xdrv - FUNC_SET_DEVICE_POWER
|
xdrv - FUNC_SET_DEVICE_POWER
|
||||||
Project tasmota Wemos 2 Version 7.0.0.3(tasmota)-STAGE
|
Project tasmota Wemos 2 Version 7.0.0.3(tasmota)-STAGE
|
||||||
|
@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Support for BS814A-2 8-button touch buttons by Peter Franck (#10447)
|
- Support for BS814A-2 8-button touch buttons by Peter Franck (#10447)
|
||||||
- Support for up to 4 I2C SEESAW_SOIL Capacitance & Temperature sensors by Peter Franck (#10481)
|
- Support for up to 4 I2C SEESAW_SOIL Capacitance & Temperature sensors by Peter Franck (#10481)
|
||||||
- ESP8266 Support for 2MB and up linker files with 1MB and up LittleFS
|
- ESP8266 Support for 2MB and up linker files with 1MB and up LittleFS
|
||||||
|
- ESP32 support for TLS MQTT using BearSSL (same as ESP8266)
|
||||||
|
|
||||||
### Breaking Changed
|
### Breaking Changed
|
||||||
- ESP32 switch from default SPIFFS to default LittleFS file system loosing current (zigbee) files
|
- ESP32 switch from default SPIFFS to default LittleFS file system loosing current (zigbee) files
|
||||||
@ -18,6 +19,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Force initial default state ``SetOption57 1`` to scan wifi network every 44 minutes for strongest signal (#10395)
|
- Force initial default state ``SetOption57 1`` to scan wifi network every 44 minutes for strongest signal (#10395)
|
||||||
|
- Command ``Sleep 0`` removes any sleep from wifi modem except when ESP32 BLE is active
|
||||||
|
|
||||||
## [9.2.0.2] 20210105
|
## [9.2.0.2] 20210105
|
||||||
### Added
|
### Added
|
||||||
|
@ -75,7 +75,7 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||||||
50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor
|
50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor
|
||||||
51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor
|
51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor
|
||||||
52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor
|
52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor
|
||||||
53 | USE_MLX90640 | xdrv_84 | MLX90640 | 0x33 | IR array temperature sensor
|
53 | USE_MLX90640 | xdrv_43 | MLX90640 | 0x33 | IR array temperature sensor
|
||||||
54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor
|
54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor
|
||||||
55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH sensor
|
55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH sensor
|
||||||
55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP sensor
|
55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP sensor
|
||||||
|
@ -96,6 +96,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
|
|||||||
- Replaced RA8876 GPIO selection from ``SPI CS`` by ``RA8876 CS``
|
- Replaced RA8876 GPIO selection from ``SPI CS`` by ``RA8876 CS``
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- Command ``Sleep 0`` removes any sleep from wifi modem except when ESP32 BLE is active
|
||||||
- Logging from heap to stack freeing 700 bytes RAM
|
- Logging from heap to stack freeing 700 bytes RAM
|
||||||
- Disabled ``USE_LIGHT`` light support for ZBBridge saving 17.6kB [#10374](https://github.com/arendst/Tasmota/issues/10374)
|
- Disabled ``USE_LIGHT`` light support for ZBBridge saving 17.6kB [#10374](https://github.com/arendst/Tasmota/issues/10374)
|
||||||
- Force initial default state ``SetOption57 1`` to scan wifi network every 44 minutes for strongest signal [#10395](https://github.com/arendst/Tasmota/issues/10395)
|
- Force initial default state ``SetOption57 1`` to scan wifi network every 44 minutes for strongest signal [#10395](https://github.com/arendst/Tasmota/issues/10395)
|
||||||
|
@ -28,14 +28,12 @@
|
|||||||
#undef WiFi
|
#undef WiFi
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void WiFiClass32::setSleepMode(int iSleepMode)
|
void WiFiClass32::setSleepMode(int iSleepMode) {
|
||||||
{
|
// WIFI_LIGHT_SLEEP and WIFI_MODEM_SLEEP
|
||||||
// WIFI_MODEM_SLEEP
|
WiFi.setSleep(iSleepMode != WIFI_NONE_SLEEP);
|
||||||
WiFi.setSleep(iSleepMode != WIFI_MODEM_SLEEP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int WiFiClass32::getPhyMode()
|
int WiFiClass32::getPhyMode() {
|
||||||
{
|
|
||||||
int phy_mode = 0; // " BGNL"
|
int phy_mode = 0; // " BGNL"
|
||||||
uint8_t protocol_bitmap;
|
uint8_t protocol_bitmap;
|
||||||
if (esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap) == ESP_OK) {
|
if (esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap) == ESP_OK) {
|
||||||
@ -47,12 +45,10 @@ int WiFiClass32::getPhyMode()
|
|||||||
return phy_mode;
|
return phy_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiClass32::wps_disable()
|
void WiFiClass32::wps_disable() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiClass32::setOutputPower(int n)
|
void WiFiClass32::setOutputPower(int n) {
|
||||||
{
|
|
||||||
wifi_power_t p = WIFI_POWER_2dBm;
|
wifi_power_t p = WIFI_POWER_2dBm;
|
||||||
if (n > 19)
|
if (n > 19)
|
||||||
p = WIFI_POWER_19_5dBm;
|
p = WIFI_POWER_19_5dBm;
|
||||||
@ -75,28 +71,23 @@ void WiFiClass32::setOutputPower(int n)
|
|||||||
WiFi.setTxPower(p);
|
WiFi.setTxPower(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiClass32::forceSleepBegin()
|
void WiFiClass32::forceSleepBegin() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiClass32::forceSleepWake()
|
void WiFiClass32::forceSleepWake() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WiFiClass32::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel, bool &hidden_scan)
|
bool WiFiClass32::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel, bool &hidden_scan) {
|
||||||
{
|
|
||||||
hidden_scan = false;
|
hidden_scan = false;
|
||||||
return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel);
|
return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_station_disconnect()
|
void wifi_station_disconnect() {
|
||||||
{
|
|
||||||
// erase ap: empty ssid, ...
|
// erase ap: empty ssid, ...
|
||||||
WiFi.disconnect(true, true);
|
WiFi.disconnect(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_station_dhcpc_start()
|
void wifi_station_dhcpc_start() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFiClass32 WiFi32;
|
WiFiClass32 WiFi32;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#define ENC_TYPE_TKIP WIFI_AUTH_WPA_WPA2_PSK
|
#define ENC_TYPE_TKIP WIFI_AUTH_WPA_WPA2_PSK
|
||||||
#define ENC_TYPE_AUTO WIFI_AUTH_MAX + 1
|
#define ENC_TYPE_AUTO WIFI_AUTH_MAX + 1
|
||||||
|
|
||||||
|
#define WIFI_NONE_SLEEP 0
|
||||||
#define WIFI_LIGHT_SLEEP 1
|
#define WIFI_LIGHT_SLEEP 1
|
||||||
#define WIFI_MODEM_SLEEP 2
|
#define WIFI_MODEM_SLEEP 2
|
||||||
|
|
||||||
|
334
pio-tools/download_fs.py
Normal file
334
pio-tools/download_fs.py
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
# Written by Maximilian Gerhardt <maximilian.gerhardt@rub.de>
|
||||||
|
# 29th December 2020
|
||||||
|
# License: Apache
|
||||||
|
# Expanded from functionality provided by PlatformIO's espressif32 and espressif8266 platforms, credited below.
|
||||||
|
# This script provides functions to download the filesystem (SPIFFS or LittleFS) from a running ESP32 / ESP8266
|
||||||
|
# over the serial bootloader using esptool.py, and mklittlefs / mkspiffs for extracting.
|
||||||
|
# run by either using the VSCode task "Custom" -> "Download Filesystem"
|
||||||
|
# or by doing 'pio run -t downloadfs' (with optional '-e <environment>') from the commandline.
|
||||||
|
# output will be saved, by default, in the "unpacked_fs" of the project.
|
||||||
|
# this folder can be changed by writing 'custom_unpack_dir = some_other_dir' in the corresponding platformio.ini
|
||||||
|
# environment.
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from os.path import isfile, join
|
||||||
|
from enum import Enum
|
||||||
|
import typing
|
||||||
|
from platformio.builder.tools.pioupload import AutodetectUploadPort
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
platform = env.PioPlatform()
|
||||||
|
board = env.BoardConfig()
|
||||||
|
mcu = board.get("build.mcu", "esp32")
|
||||||
|
# Hack for using mklittlefs instead of mkspiffs -> needed since littlefs is not supported with this for ESP32
|
||||||
|
if env["PIOPLATFORM"] == "espressif32":
|
||||||
|
#print("Replace MKSPIFFSTOOL with mklittlefs")
|
||||||
|
env.Replace( MKSPIFFSTOOL=platform.get_package_dir("tool-mklittlefs") + '/mklittlefs' )
|
||||||
|
|
||||||
|
# needed for later
|
||||||
|
AutodetectUploadPort(env)
|
||||||
|
|
||||||
|
class FSType(Enum):
|
||||||
|
SPIFFS="spiffs"
|
||||||
|
LITTLEFS="littlefs"
|
||||||
|
FATFS="fatfs"
|
||||||
|
|
||||||
|
class FSInfo:
|
||||||
|
def __init__(self, fs_type, start, length, page_size, block_size):
|
||||||
|
self.fs_type = fs_type
|
||||||
|
self.start = start
|
||||||
|
self.length = length
|
||||||
|
self.page_size = page_size
|
||||||
|
self.block_size = block_size
|
||||||
|
def __repr__(self):
|
||||||
|
return f"FS type {self.fs_type} Start {hex(self.start)} Len {self.length} Page size {self.page_size} Block size {self.block_size}"
|
||||||
|
# extract command supposed to be implemented by subclasses
|
||||||
|
def get_extract_cmd(self, input_file, output_dir):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
class LittleFSInfo(FSInfo):
|
||||||
|
def __init__(self, start, length, page_size, block_size):
|
||||||
|
if env["PIOPLATFORM"] == "espressif32":
|
||||||
|
#for ESP32: retrieve and evaluate, e.g. to mkspiffs_espressif32_arduino
|
||||||
|
self.tool = env.subst(env["MKSPIFFSTOOL"])
|
||||||
|
else:
|
||||||
|
self.tool = env["MKFSTOOL"] # from mkspiffs package
|
||||||
|
self.tool = join(platform.get_package_dir("tool-mklittlefs"), self.tool)
|
||||||
|
super().__init__(FSType.LITTLEFS, start, length, page_size, block_size)
|
||||||
|
def __repr__(self):
|
||||||
|
return f"FS type {self.fs_type} Start {hex(self.start)} Len {self.length} Page size {self.page_size} Block size {self.block_size} Tool: {self.tool}"
|
||||||
|
def get_extract_cmd(self, input_file, output_dir):
|
||||||
|
return [self.tool, "-b", str(self.block_size), "-p", str(self.page_size), "--unpack", output_dir, input_file]
|
||||||
|
|
||||||
|
|
||||||
|
class SPIFFSInfo(FSInfo):
|
||||||
|
def __init__(self, start, length, page_size, block_size):
|
||||||
|
if env["PIOPLATFORM"] == "espressif32":
|
||||||
|
#for ESP32: retrieve and evaluate, e.g. to mkspiffs_espressif32_arduino
|
||||||
|
self.tool = env.subst(env["MKSPIFFSTOOL"])
|
||||||
|
else:
|
||||||
|
self.tool = env["MKFSTOOL"] # from mkspiffs package
|
||||||
|
self.tool = join(platform.get_package_dir("tool-mkspiffs"), self.tool)
|
||||||
|
super().__init__(FSType.SPIFFS, start, length, page_size, block_size)
|
||||||
|
def __repr__(self):
|
||||||
|
return f"FS type {self.fs_type} Start {hex(self.start)} Len {self.length} Page size {self.page_size} Block size {self.block_size} Tool: {self.tool}"
|
||||||
|
def get_extract_cmd(self, input_file, output_dir):
|
||||||
|
return f'"{self.tool}" -b {self.block_size} -p {self.page_size} --unpack "{output_dir}" "{input_file}"'
|
||||||
|
|
||||||
|
# SPIFFS helpers copied from ESP32, https://github.com/platformio/platform-espressif32/blob/develop/builder/main.py
|
||||||
|
# Copyright 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
||||||
|
def _parse_size(value):
|
||||||
|
if isinstance(value, int):
|
||||||
|
return value
|
||||||
|
elif value.isdigit():
|
||||||
|
return int(value)
|
||||||
|
elif value.startswith("0x"):
|
||||||
|
return int(value, 16)
|
||||||
|
elif value[-1].upper() in ("K", "M"):
|
||||||
|
base = 1024 if value[-1].upper() == "K" else 1024 * 1024
|
||||||
|
return int(value[:-1]) * base
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _parse_partitions(env):
|
||||||
|
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
|
||||||
|
if not isfile(partitions_csv):
|
||||||
|
sys.stderr.write("Could not find the file %s with partitions "
|
||||||
|
"table.\n" % partitions_csv)
|
||||||
|
env.Exit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
result = []
|
||||||
|
next_offset = 0
|
||||||
|
with open(partitions_csv) as fp:
|
||||||
|
for line in fp.readlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
tokens = [t.strip() for t in line.split(",")]
|
||||||
|
if len(tokens) < 5:
|
||||||
|
continue
|
||||||
|
partition = {
|
||||||
|
"name": tokens[0],
|
||||||
|
"type": tokens[1],
|
||||||
|
"subtype": tokens[2],
|
||||||
|
"offset": tokens[3] or next_offset,
|
||||||
|
"size": tokens[4],
|
||||||
|
"flags": tokens[5] if len(tokens) > 5 else None
|
||||||
|
}
|
||||||
|
result.append(partition)
|
||||||
|
next_offset = (_parse_size(partition['offset']) +
|
||||||
|
_parse_size(partition['size']))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def esp32_fetch_spiffs_size(env):
|
||||||
|
spiffs = None
|
||||||
|
for p in _parse_partitions(env):
|
||||||
|
if p['type'] == "data" and p['subtype'] == "spiffs":
|
||||||
|
spiffs = p
|
||||||
|
if not spiffs:
|
||||||
|
sys.stderr.write(
|
||||||
|
env.subst("Could not find the `spiffs` section in the partitions "
|
||||||
|
"table $PARTITIONS_TABLE_CSV\n"))
|
||||||
|
env.Exit(1)
|
||||||
|
return
|
||||||
|
env["SPIFFS_START"] = _parse_size(spiffs['offset'])
|
||||||
|
env["SPIFFS_SIZE"] = _parse_size(spiffs['size'])
|
||||||
|
env["SPIFFS_PAGE"] = int("0x100", 16)
|
||||||
|
env["SPIFFS_BLOCK"] = int("0x1000", 16)
|
||||||
|
|
||||||
|
## FS helpers for ESP8266
|
||||||
|
# copied from https://github.com/platformio/platform-espressif8266/blob/develop/builder/main.py
|
||||||
|
# Copyright 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
||||||
|
def _get_board_f_flash(env):
|
||||||
|
frequency = env.subst("$BOARD_F_FLASH")
|
||||||
|
frequency = str(frequency).replace("L", "")
|
||||||
|
return int(int(frequency) / 1000000)
|
||||||
|
|
||||||
|
def _parse_ld_sizes(ldscript_path):
|
||||||
|
assert ldscript_path
|
||||||
|
result = {}
|
||||||
|
# get flash size from board's manifest
|
||||||
|
result['flash_size'] = int(env.BoardConfig().get("upload.maximum_size", 0))
|
||||||
|
# get flash size from LD script path
|
||||||
|
match = re.search(r"\.flash\.(\d+[mk]).*\.ld", ldscript_path)
|
||||||
|
if match:
|
||||||
|
result['flash_size'] = _parse_size(match.group(1))
|
||||||
|
|
||||||
|
appsize_re = re.compile(
|
||||||
|
r"irom0_0_seg\s*:.+len\s*=\s*(0x[\da-f]+)", flags=re.I)
|
||||||
|
filesystem_re = re.compile(
|
||||||
|
r"PROVIDE\s*\(\s*_%s_(\w+)\s*=\s*(0x[\da-f]+)\s*\)" % "FS"
|
||||||
|
if "arduino" in env.subst("$PIOFRAMEWORK")
|
||||||
|
else "SPIFFS",
|
||||||
|
flags=re.I,
|
||||||
|
)
|
||||||
|
with open(ldscript_path) as fp:
|
||||||
|
for line in fp.readlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith("/*"):
|
||||||
|
continue
|
||||||
|
match = appsize_re.search(line)
|
||||||
|
if match:
|
||||||
|
result['app_size'] = _parse_size(match.group(1))
|
||||||
|
continue
|
||||||
|
match = filesystem_re.search(line)
|
||||||
|
if match:
|
||||||
|
result['fs_%s' % match.group(1)] = _parse_size(
|
||||||
|
match.group(2))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _get_flash_size(env):
|
||||||
|
ldsizes = _parse_ld_sizes(env.GetActualLDScript())
|
||||||
|
if ldsizes['flash_size'] < 1048576:
|
||||||
|
return "%dK" % (ldsizes['flash_size'] / 1024)
|
||||||
|
return "%dM" % (ldsizes['flash_size'] / 1048576)
|
||||||
|
|
||||||
|
def esp8266_fetch_fs_size(env):
|
||||||
|
ldsizes = _parse_ld_sizes(env.GetActualLDScript())
|
||||||
|
for key in ldsizes:
|
||||||
|
if key.startswith("fs_"):
|
||||||
|
env[key.upper()] = ldsizes[key]
|
||||||
|
|
||||||
|
assert all([
|
||||||
|
k in env
|
||||||
|
for k in ["FS_START", "FS_END", "FS_PAGE", "FS_BLOCK"]
|
||||||
|
])
|
||||||
|
|
||||||
|
# esptool flash starts from 0
|
||||||
|
for k in ("FS_START", "FS_END"):
|
||||||
|
_value = 0
|
||||||
|
if env[k] < 0x40300000:
|
||||||
|
_value = env[k] & 0xFFFFF
|
||||||
|
elif env[k] < 0x411FB000:
|
||||||
|
_value = env[k] & 0xFFFFFF
|
||||||
|
_value -= 0x200000 # correction
|
||||||
|
else:
|
||||||
|
_value = env[k] & 0xFFFFFF
|
||||||
|
_value += 0xE00000 # correction
|
||||||
|
|
||||||
|
env[k] = _value
|
||||||
|
|
||||||
|
def esp8266_get_esptoolpy_reset_flags(resetmethod):
|
||||||
|
# no dtr, no_sync
|
||||||
|
resets = ("no_reset_no_sync", "soft_reset")
|
||||||
|
if resetmethod == "nodemcu":
|
||||||
|
# dtr
|
||||||
|
resets = ("default_reset", "hard_reset")
|
||||||
|
elif resetmethod == "ck":
|
||||||
|
# no dtr
|
||||||
|
resets = ("no_reset", "soft_reset")
|
||||||
|
|
||||||
|
return ["--before", resets[0], "--after", resets[1]]
|
||||||
|
|
||||||
|
## Script interface functions
|
||||||
|
|
||||||
|
def get_fs_type_start_and_length():
|
||||||
|
platform = env["PIOPLATFORM"]
|
||||||
|
if platform == "espressif32":
|
||||||
|
print("Retrieving filesystem info for ESP32. Assuming SPIFFS.")
|
||||||
|
print("Partition file: " + str(env.subst("$PARTITIONS_TABLE_CSV")))
|
||||||
|
esp32_fetch_spiffs_size(env)
|
||||||
|
return SPIFFSInfo(env["SPIFFS_START"], env["SPIFFS_SIZE"], env["SPIFFS_PAGE"], env["SPIFFS_BLOCK"])
|
||||||
|
elif platform == "espressif8266":
|
||||||
|
print("Retrieving filesystem info for ESP8266.")
|
||||||
|
filesystem = board.get("build.filesystem", "spiffs")
|
||||||
|
if filesystem not in ("spiffs", "littlefs"):
|
||||||
|
print("Unrecognized board_build.filesystem option '" + str(filesystem) + "'.")
|
||||||
|
env.Exit(1)
|
||||||
|
# fetching sizes is the same for all filesystems
|
||||||
|
esp8266_fetch_fs_size(env)
|
||||||
|
print("FS_START: " + hex(env["FS_START"]))
|
||||||
|
print("FS_END: " + hex(env["FS_END"]))
|
||||||
|
print("FS_PAGE: " + hex(env["FS_PAGE"]))
|
||||||
|
print("FS_BLOCK: " + hex(env["FS_BLOCK"]))
|
||||||
|
if filesystem == "spiffs":
|
||||||
|
print("Recognized SPIFFS filesystem.")
|
||||||
|
return SPIFFSInfo(env["FS_START"], env["FS_END"] - env["FS_START"], env["FS_PAGE"], env["FS_BLOCK"])
|
||||||
|
elif filesystem == "littlefs":
|
||||||
|
print("Recognized LittleFS filesystem.")
|
||||||
|
return LittleFSInfo(env["FS_START"], env["FS_END"] - env["FS_START"], env["FS_PAGE"], env["FS_BLOCK"])
|
||||||
|
else:
|
||||||
|
print("Unrecongized configuration.")
|
||||||
|
pass
|
||||||
|
|
||||||
|
def download_fs(fs_info: FSInfo):
|
||||||
|
esptoolpy = join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py")
|
||||||
|
fs_file = join(env["PROJECT_DIR"], f"downloaded_fs_{hex(fs_info.start)}_{hex(fs_info.length)}.bin")
|
||||||
|
esptoolpy_flags = [
|
||||||
|
"--chip", mcu,
|
||||||
|
"--port", env.subst("$UPLOAD_PORT"),
|
||||||
|
"--baud", env.subst("$UPLOAD_SPEED"),
|
||||||
|
"--before", "default_reset",
|
||||||
|
"--after", "hard_reset",
|
||||||
|
"read_flash",
|
||||||
|
hex(fs_info.start),
|
||||||
|
hex(fs_info.length),
|
||||||
|
fs_file
|
||||||
|
]
|
||||||
|
esptoolpy_cmd = [env["PYTHONEXE"], esptoolpy] + esptoolpy_flags
|
||||||
|
print("Executing flash download command.")
|
||||||
|
print(esptoolpy_cmd)
|
||||||
|
try:
|
||||||
|
returncode = subprocess.call(esptoolpy_cmd, shell=False)
|
||||||
|
print("Downloaded filesystem binary.")
|
||||||
|
return (True, fs_file)
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
print("Downloading failed with " + str(exc))
|
||||||
|
return (False, "")
|
||||||
|
|
||||||
|
def unpack_fs(fs_info: FSInfo, downloaded_file: str):
|
||||||
|
# by writing custom_unpack_dir = some_dir in the platformio.ini, one can
|
||||||
|
# control the unpack directory
|
||||||
|
unpack_dir = env.GetProjectOption("custom_unpack_dir", "unpacked_fs")
|
||||||
|
#unpack_dir = "unpacked_fs"
|
||||||
|
try:
|
||||||
|
if os.path.exists(unpack_dir):
|
||||||
|
shutil.rmtree(unpack_dir)
|
||||||
|
except Exception as exc:
|
||||||
|
print("Exception while attempting to remove the folder '" + str(unpack_dir) + "': " + str(exc))
|
||||||
|
if not os.path.exists(unpack_dir):
|
||||||
|
os.makedirs(unpack_dir)
|
||||||
|
|
||||||
|
cmd = fs_info.get_extract_cmd(downloaded_file, unpack_dir)
|
||||||
|
print("Executing extraction command: " + str(cmd))
|
||||||
|
try:
|
||||||
|
returncode = subprocess.call(cmd, shell=False)
|
||||||
|
print("Unpacked filesystem.")
|
||||||
|
return (True, unpack_dir)
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
print("Unpacking filesystem failed with " + str(exc))
|
||||||
|
return (False, "")
|
||||||
|
|
||||||
|
def display_fs(extracted_dir):
|
||||||
|
# extract command already nicely lists all extracted files.
|
||||||
|
# no need to display that ourselves. just display a summary
|
||||||
|
file_count = sum([len(files) for r, d, files in os.walk(extracted_dir)])
|
||||||
|
print("Extracted " + str(file_count) + " file(s) from filesystem.")
|
||||||
|
|
||||||
|
def command_download_fs(*args, **kwargs):
|
||||||
|
print("Entrypoint")
|
||||||
|
#print(env.Dump())
|
||||||
|
info = get_fs_type_start_and_length()
|
||||||
|
print("Parsed FS info: " + str(info))
|
||||||
|
download_ok, downloaded_file = download_fs(info)
|
||||||
|
print("Download was okay: " + str(download_ok) + ". File at: "+ str(downloaded_file))
|
||||||
|
unpack_ok, unpacked_dir = unpack_fs(info, downloaded_file)
|
||||||
|
if unpack_ok is True:
|
||||||
|
display_fs(unpacked_dir)
|
||||||
|
|
||||||
|
env.AddCustomTarget(
|
||||||
|
name="downloadfs",
|
||||||
|
dependencies=None,
|
||||||
|
actions=[
|
||||||
|
command_download_fs
|
||||||
|
],
|
||||||
|
title="Download Filesystem",
|
||||||
|
description="Downloads and displays files stored in the target ESP32/ESP8266"
|
||||||
|
)
|
@ -66,6 +66,8 @@ default_envs = ${build_envs.default_envs}
|
|||||||
[common]
|
[common]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp01_1m
|
board = esp01_1m
|
||||||
|
board_build.filesystem = littlefs
|
||||||
|
custom_unpack_dir = unpacked_littlefs
|
||||||
board_build.flash_mode = dout
|
board_build.flash_mode = dout
|
||||||
board_build.ldscript = eagle.flash.1m.ld
|
board_build.ldscript = eagle.flash.1m.ld
|
||||||
|
|
||||||
@ -76,7 +78,8 @@ build_flags = ${core.build_flags}
|
|||||||
|
|
||||||
board_build.f_cpu = 80000000L
|
board_build.f_cpu = 80000000L
|
||||||
board_build.f_flash = 40000000L
|
board_build.f_flash = 40000000L
|
||||||
monitor_speed = 115200
|
monitor_speed = 74880
|
||||||
|
monitor_port = COM5
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
; *** Upload Serial reset method for Wemos and NodeMCU
|
; *** Upload Serial reset method for Wemos and NodeMCU
|
||||||
upload_resetmethod = nodemcu
|
upload_resetmethod = nodemcu
|
||||||
@ -98,6 +101,7 @@ extra_scripts = pio-tools/strip-floats.py
|
|||||||
pio-tools/name-firmware.py
|
pio-tools/name-firmware.py
|
||||||
pio-tools/gzip-firmware.py
|
pio-tools/gzip-firmware.py
|
||||||
pio-tools/override_copy.py
|
pio-tools/override_copy.py
|
||||||
|
pio-tools/download_fs.py
|
||||||
|
|
||||||
[esp_defaults]
|
[esp_defaults]
|
||||||
; *** remove undesired all warnings
|
; *** remove undesired all warnings
|
||||||
|
@ -48,6 +48,19 @@ build_flags = ${core.build_flags}
|
|||||||
; -DDEBUG_TASMOTA_DRIVER
|
; -DDEBUG_TASMOTA_DRIVER
|
||||||
; -DDEBUG_TASMOTA_SENSOR
|
; -DDEBUG_TASMOTA_SENSOR
|
||||||
|
|
||||||
|
; *** CAUTION *** This setting is ONLY possible since 12.01.2021 with development version !!!
|
||||||
|
; *** Enable only if you exactly know what are you doing
|
||||||
|
; *** If you try with earlier builds a serial erase and flash is probably needed
|
||||||
|
;
|
||||||
|
; Build variant 1MB = 1MB firmware no filesystem (default)
|
||||||
|
;board_build.ldscript = eagle.flash.1m.ld
|
||||||
|
; Build variant 2MB = 1MB firmware, +744k OTA, 256k filesystem (Zigbee Bridge, most Shelly devices)
|
||||||
|
;board_build.ldscript = eagle.flash.2m256.ld
|
||||||
|
; Build variant 4MB = 1MB firmware, +1MB OTA, 2MB filesystem (WEMOS D1 Mini, NodeMCU, Sonoff POW)
|
||||||
|
;board_build.ldscript = eagle.flash.4m2m.ld
|
||||||
|
; Build variant 16MB = 1MB firmware, +1MB OTA, 14MB filesystem (WEMOS D1 Mini pro, Ledunia (=32MB))
|
||||||
|
;board_build.ldscript = eagle.flash.16m14m.ld
|
||||||
|
|
||||||
; set CPU frequency to 80MHz (default) or 160MHz
|
; set CPU frequency to 80MHz (default) or 160MHz
|
||||||
;board_build.f_cpu = 160000000L
|
;board_build.f_cpu = 160000000L
|
||||||
|
|
||||||
@ -103,39 +116,27 @@ build_flags = ${esp82xx_defaults.build_flags}
|
|||||||
-DWAVEFORM_LOCKED_PWM
|
-DWAVEFORM_LOCKED_PWM
|
||||||
-Wno-switch-unreachable
|
-Wno-switch-unreachable
|
||||||
|
|
||||||
|
|
||||||
[common32]
|
[common32]
|
||||||
platform = ${core32.platform}
|
|
||||||
platform_packages = ${core32.platform_packages}
|
platform_packages = ${core32.platform_packages}
|
||||||
build_unflags = ${core32.build_unflags}
|
build_unflags = ${core32.build_unflags}
|
||||||
build_flags = ${core32.build_flags}
|
build_flags = ${core32.build_flags}
|
||||||
board = esp32dev
|
upload_port = COM4
|
||||||
board_build.ldscript = esp32_out.ld
|
|
||||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
|
||||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
|
||||||
board_build.f_flash = ${common.board_build.f_flash}
|
|
||||||
board_build.f_cpu = ${common.board_build.f_cpu}
|
|
||||||
monitor_speed = ${common.monitor_speed}
|
|
||||||
upload_port = ${common.upload_port}
|
|
||||||
upload_resetmethod = ${common.upload_resetmethod}
|
|
||||||
upload_speed = 921600
|
|
||||||
extra_scripts = ${common.extra_scripts}
|
|
||||||
lib_extra_dirs = ${library.lib_extra_dirs}
|
lib_extra_dirs = ${library.lib_extra_dirs}
|
||||||
; *** ESP32 lib. ALWAYS needed for ESP32 !!!
|
; *** ESP32 lib. ALWAYS needed for ESP32 !!!
|
||||||
lib/libesp32
|
lib/libesp32
|
||||||
|
|
||||||
[core32]
|
[core32]
|
||||||
; Activate Stage Core32 by removing ";" in next 3 lines, if you want to override the standard core32
|
; Activate Stage Core32 by removing ";" in next 3 lines, if you want to override the standard core32
|
||||||
;platform_packages = ${core32_stage.platform_packages}
|
;platform_packages = ${core32_stage.platform_packages}
|
||||||
;build_unflags = ${core32_stage.build_unflags}
|
;build_unflags = ${core32_stage.build_unflags}
|
||||||
;build_flags = ${core32_stage.build_flags}
|
;build_flags = ${core32_stage.build_flags}
|
||||||
|
|
||||||
|
|
||||||
[core32_stage]
|
[core32_stage]
|
||||||
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2452c1fb539246e47a715b74a3ad25b8a7ebbec7
|
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/1.0.5-rc6/esp32-1.0.5-rc6.zip
|
||||||
platformio/tool-mklittlefs @ ~1.203.200522
|
platformio/tool-mklittlefs @ ~1.203.200522
|
||||||
build_unflags = ${esp32_defaults.build_unflags}
|
build_unflags = ${esp32_defaults.build_unflags}
|
||||||
build_flags = ${esp32_defaults.build_flags}
|
build_flags = ${esp32_defaults.build_flags}
|
||||||
-DESP32_STAGE=true
|
;-DESP32_STAGE=true
|
||||||
|
|
||||||
[library]
|
[library]
|
||||||
lib_ldf_mode = chain+
|
lib_ldf_mode = chain+
|
||||||
@ -165,6 +166,7 @@ lib_extra_dirs =
|
|||||||
[env:tasmota32solo1]
|
[env:tasmota32solo1]
|
||||||
extends = env:tasmota32
|
extends = env:tasmota32
|
||||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/raw/framework-arduinoespressif32/framework-arduinoespressif32-release_v3.3-solo1-4b325f52e.tar.gz
|
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/raw/framework-arduinoespressif32/framework-arduinoespressif32-release_v3.3-solo1-4b325f52e.tar.gz
|
||||||
|
platformio/tool-mklittlefs @ ~1.203.200522
|
||||||
platformio/tool-esptoolpy @ ~1.30000.0
|
platformio/tool-esptoolpy @ ~1.30000.0
|
||||||
build_unflags = ${esp32_defaults.build_unflags}
|
build_unflags = ${esp32_defaults.build_unflags}
|
||||||
build_flags = ${common32.build_flags}
|
build_flags = ${common32.build_flags}
|
||||||
|
@ -47,6 +47,8 @@ platform_packages = ${core32.platform_packages}
|
|||||||
build_unflags = ${core32.build_unflags}
|
build_unflags = ${core32.build_unflags}
|
||||||
build_flags = ${core32.build_flags}
|
build_flags = ${core32.build_flags}
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
|
board_build.filesystem = ${common.board_build.filesystem}
|
||||||
|
custom_unpack_dir = ${common.custom_unpack_dir}
|
||||||
board_build.ldscript = esp32_out.ld
|
board_build.ldscript = esp32_out.ld
|
||||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
||||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
board_build.flash_mode = ${common.board_build.flash_mode}
|
||||||
|
@ -3,6 +3,7 @@ platform = ${common.platform}
|
|||||||
platform_packages = ${common.platform_packages}
|
platform_packages = ${common.platform_packages}
|
||||||
framework = ${common.framework}
|
framework = ${common.framework}
|
||||||
board = ${common.board}
|
board = ${common.board}
|
||||||
|
board_build.filesystem = ${common.board_build.filesystem}
|
||||||
board_build.ldscript = ${common.board_build.ldscript}
|
board_build.ldscript = ${common.board_build.ldscript}
|
||||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
board_build.flash_mode = ${common.board_build.flash_mode}
|
||||||
board_build.f_flash = ${common.board_build.f_flash}
|
board_build.f_flash = ${common.board_build.f_flash}
|
||||||
@ -64,6 +65,7 @@ build_flags = ${common.build_flags} ${irremoteesp_full.build_flags}
|
|||||||
|
|
||||||
[env:tasmota-zbbridge]
|
[env:tasmota-zbbridge]
|
||||||
build_flags = ${common.build_flags} -DFIRMWARE_ZBBRIDGE
|
build_flags = ${common.build_flags} -DFIRMWARE_ZBBRIDGE
|
||||||
|
board_build.ldscript = eagle.flash.2m256.ld
|
||||||
board_build.f_cpu = 160000000L
|
board_build.f_cpu = 160000000L
|
||||||
lib_extra_dirs = lib/lib_ssl
|
lib_extra_dirs = lib/lib_ssl
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "my_user_config.h"
|
#include "my_user_config.h"
|
||||||
#include "tasmota_configurations.h"
|
#include "tasmota_configurations.h"
|
||||||
|
|
||||||
|
#if defined(ESP8266) && defined(USE_TLS)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "StackThunk_light.h"
|
#include "StackThunk_light.h"
|
||||||
@ -121,27 +122,29 @@ uint32_t stack_thunk_light_get_max_usage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Print the stack from the first used 16-byte chunk to the top, decodable by the exception decoder */
|
/* Print the stack from the first used 16-byte chunk to the top, decodable by the exception decoder */
|
||||||
void stack_thunk_light_dump_stack()
|
// void stack_thunk_light_dump_stack()
|
||||||
{
|
// {
|
||||||
uint32_t *pos = stack_thunk_light_top;
|
// uint32_t *pos = stack_thunk_light_top;
|
||||||
while (pos < stack_thunk_light_ptr) {
|
// while (pos < stack_thunk_light_ptr) {
|
||||||
if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
|
// if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
|
||||||
break;
|
// break;
|
||||||
pos += 4;
|
// pos += 4;
|
||||||
}
|
// }
|
||||||
ets_printf(">>>stack>>>\n");
|
// ets_printf(">>>stack>>>\n");
|
||||||
while (pos < stack_thunk_light_ptr) {
|
// while (pos < stack_thunk_light_ptr) {
|
||||||
ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]);
|
// ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]);
|
||||||
pos += 4;
|
// pos += 4;
|
||||||
}
|
// }
|
||||||
ets_printf("<<<stack<<<\n");
|
// ets_printf("<<<stack<<<\n");
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* Called when the stack overflow is detected by a thunk. Main memory is corrupted at this point. Do not return. */
|
/* Called when the stack overflow is detected by a thunk. Main memory is corrupted at this point. Do not return. */
|
||||||
void stack_thunk_light_fatal_overflow()
|
void stack_thunk_light_fatal_overflow()
|
||||||
{
|
{
|
||||||
ets_printf("FATAL ERROR: BSSL stack overflow\n");
|
// ets_printf("FATAL ERROR: BSSL stack overflow\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "my_user_config.h"
|
#include "my_user_config.h"
|
||||||
#include "tasmota_configurations.h"
|
#include "tasmota_configurations.h"
|
||||||
#if defined(ESP8266) && defined(USE_TLS)
|
#if defined(USE_TLS)
|
||||||
|
|
||||||
// #define DEBUG_TLS
|
// #define DEBUG_TLS
|
||||||
// #define DEBUG_ESP_SSL
|
// #define DEBUG_ESP_SSL
|
||||||
@ -47,7 +47,9 @@ extern "C" {
|
|||||||
#include "lwip/tcp.h"
|
#include "lwip/tcp.h"
|
||||||
#include "lwip/inet.h"
|
#include "lwip/inet.h"
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
#include <include/ClientContext.h>
|
#ifdef ESP8266
|
||||||
|
#include <include/ClientContext.h>
|
||||||
|
#endif
|
||||||
#include "c_types.h"
|
#include "c_types.h"
|
||||||
|
|
||||||
#include <core_version.h>
|
#include <core_version.h>
|
||||||
@ -57,11 +59,15 @@ extern "C" {
|
|||||||
#include "coredecls.h"
|
#include "coredecls.h"
|
||||||
#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
|
#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
|
||||||
void _Log_heap_size(const char *msg) {
|
void _Log_heap_size(const char *msg) {
|
||||||
|
#ifdef ESP8266
|
||||||
register uint32_t *sp asm("a1");
|
register uint32_t *sp asm("a1");
|
||||||
int freestack = 4 * (sp - g_pcont->stack);
|
int freestack = 4 * (sp - g_pcont->stack);
|
||||||
Serial.printf("%s %d, Fragmentation=%d, Thunkstack=%d, Free stack=%d, FreeContStack=%d\n",
|
Serial.printf("%s %d, Fragmentation=%d, Thunkstack=%d, Free stack=%d, FreeContStack=%d\n",
|
||||||
msg, ESP.getFreeHeap(), ESP.getHeapFragmentation(), stack_thunk_light_get_max_usage(),
|
msg, ESP.getFreeHeap(), ESP.getHeapFragmentation(), stack_thunk_light_get_max_usage(),
|
||||||
freestack, ESP.getFreeContStack());
|
freestack, ESP.getFreeContStack());
|
||||||
|
#elif defined(ESP32)
|
||||||
|
Serial.printf("> Heap %s = %d\n", msg, uxTaskGetStackHighWaterMark(nullptr));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define LOG_HEAP_SIZE(a)
|
#define LOG_HEAP_SIZE(a)
|
||||||
@ -71,6 +77,7 @@ void _Log_heap_size(const char *msg) {
|
|||||||
extern uint32_t UtcTime(void);
|
extern uint32_t UtcTime(void);
|
||||||
extern uint32_t CfgTime(void);
|
extern uint32_t CfgTime(void);
|
||||||
|
|
||||||
|
#ifdef ESP8266 // Stack thunk is not needed with ESP32
|
||||||
// Stack thunked versions of calls
|
// Stack thunked versions of calls
|
||||||
// Initially in BearSSLHelpers.h
|
// Initially in BearSSLHelpers.h
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -164,6 +171,8 @@ unsigned char *min_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, si
|
|||||||
#define br_ssl_engine_sendrec_ack min_br_ssl_engine_sendrec_ack
|
#define br_ssl_engine_sendrec_ack min_br_ssl_engine_sendrec_ack
|
||||||
#define br_ssl_engine_sendrec_buf min_br_ssl_engine_sendrec_buf
|
#define br_ssl_engine_sendrec_buf min_br_ssl_engine_sendrec_buf
|
||||||
|
|
||||||
|
#endif // ESP8266
|
||||||
|
|
||||||
//#define DEBUG_ESP_SSL
|
//#define DEBUG_ESP_SSL
|
||||||
#ifdef DEBUG_ESP_SSL
|
#ifdef DEBUG_ESP_SSL
|
||||||
//#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
|
//#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
|
||||||
@ -201,19 +210,23 @@ void WiFiClientSecure_light::_clear() {
|
|||||||
// Constructor
|
// Constructor
|
||||||
WiFiClientSecure_light::WiFiClientSecure_light(int recv, int xmit) : WiFiClient() {
|
WiFiClientSecure_light::WiFiClientSecure_light(int recv, int xmit) : WiFiClient() {
|
||||||
_clear();
|
_clear();
|
||||||
LOG_HEAP_SIZE("StackThunk before");
|
// LOG_HEAP_SIZE("StackThunk before");
|
||||||
//stack_thunk_light_add_ref();
|
//stack_thunk_light_add_ref();
|
||||||
LOG_HEAP_SIZE("StackThunk after");
|
// LOG_HEAP_SIZE("StackThunk after");
|
||||||
// now finish the setup
|
// now finish the setup
|
||||||
setBufferSizes(recv, xmit); // reasonable minimum
|
setBufferSizes(recv, xmit); // reasonable minimum
|
||||||
allocateBuffers();
|
allocateBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFiClientSecure_light::~WiFiClientSecure_light() {
|
WiFiClientSecure_light::~WiFiClientSecure_light() {
|
||||||
|
#ifdef ESP8266
|
||||||
if (_client) {
|
if (_client) {
|
||||||
_client->unref();
|
_client->unref();
|
||||||
_client = nullptr;
|
_client = nullptr;
|
||||||
}
|
}
|
||||||
|
#elif defined(ESP32)
|
||||||
|
stop();
|
||||||
|
#endif
|
||||||
//_cipher_list = nullptr; // std::shared will free if last reference
|
//_cipher_list = nullptr; // std::shared will free if last reference
|
||||||
_freeSSL();
|
_freeSSL();
|
||||||
}
|
}
|
||||||
@ -258,6 +271,7 @@ void WiFiClientSecure_light::setBufferSizes(int recv, int xmit) {
|
|||||||
_iobuf_out_size = xmit;
|
_iobuf_out_size = xmit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
bool WiFiClientSecure_light::stop(unsigned int maxWaitMs) {
|
bool WiFiClientSecure_light::stop(unsigned int maxWaitMs) {
|
||||||
bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
|
bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
|
||||||
_freeSSL();
|
_freeSSL();
|
||||||
@ -268,6 +282,17 @@ bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
|
|||||||
(void) _run_until(BR_SSL_SENDAPP);
|
(void) _run_until(BR_SSL_SENDAPP);
|
||||||
return WiFiClient::flush(maxWaitMs);
|
return WiFiClient::flush(maxWaitMs);
|
||||||
}
|
}
|
||||||
|
#elif defined(ESP32)
|
||||||
|
void WiFiClientSecure_light::stop(void) {
|
||||||
|
WiFiClient::stop(); // calls our virtual flush()
|
||||||
|
_freeSSL();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiClientSecure_light::flush(void) {
|
||||||
|
(void) _run_until(BR_SSL_SENDAPP);
|
||||||
|
WiFiClient::flush();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
|
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
|
||||||
DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
|
DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
|
||||||
@ -307,7 +332,11 @@ void WiFiClientSecure_light::_freeSSL() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WiFiClientSecure_light::_clientConnected() {
|
bool WiFiClientSecure_light::_clientConnected() {
|
||||||
|
#ifdef ESP8266
|
||||||
return (_client && _client->state() == ESTABLISHED);
|
return (_client && _client->state() == ESTABLISHED);
|
||||||
|
#elif defined(ESP32)
|
||||||
|
return WiFiClient::connected();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t WiFiClientSecure_light::connected() {
|
uint8_t WiFiClientSecure_light::connected() {
|
||||||
@ -489,7 +518,7 @@ size_t WiFiClientSecure_light::peekBytes(uint8_t *buffer, size_t length) {
|
|||||||
achieved, this function returns 0. On error, it returns -1.
|
achieved, this function returns 0. On error, it returns -1.
|
||||||
*/
|
*/
|
||||||
int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
|
int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
|
||||||
//LOG_HEAP_SIZE("_run_until 1");
|
//LOG_HEAP_SIZE("_run_until 1");
|
||||||
if (!ctx_present()) {
|
if (!ctx_present()) {
|
||||||
DEBUG_BSSL("_run_until: Not connected\n");
|
DEBUG_BSSL("_run_until: Not connected\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -506,9 +535,15 @@ int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) {
|
if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) {
|
||||||
return (state & target) ? 0 : -1;
|
return (state & target) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
#elif defined(ESP32)
|
||||||
|
if (!_clientConnected() && !WiFiClient::available()) {
|
||||||
|
return (state & target) ? 0 : -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If there is some record data to send, do it. This takes
|
If there is some record data to send, do it. This takes
|
||||||
@ -898,12 +933,16 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||||||
do { // used to exit on Out of Memory error and keep all cleanup code at the same place
|
do { // used to exit on Out of Memory error and keep all cleanup code at the same place
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// allocate Thunk stack, move to alternate stack and initialize
|
// allocate Thunk stack, move to alternate stack and initialize
|
||||||
|
#ifdef ESP8266
|
||||||
stack_thunk_light_add_ref();
|
stack_thunk_light_add_ref();
|
||||||
|
#endif // ESP8266
|
||||||
LOG_HEAP_SIZE("Thunk allocated");
|
LOG_HEAP_SIZE("Thunk allocated");
|
||||||
DEBUG_BSSL("_connectSSL: start connection\n");
|
DEBUG_BSSL("_connectSSL: start connection\n");
|
||||||
_freeSSL();
|
_freeSSL();
|
||||||
clearLastError();
|
clearLastError();
|
||||||
if (!stack_thunk_light_get_stack_bot()) break;
|
#ifdef ESP8266
|
||||||
|
if (!stack_thunk_light_get_stack_bot()) break;
|
||||||
|
#endif // ESP8266
|
||||||
|
|
||||||
_ctx_present = true;
|
_ctx_present = true;
|
||||||
_eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
|
_eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
|
||||||
@ -964,10 +1003,12 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
LOG_HEAP_SIZE("_connectSSL.end");
|
LOG_HEAP_SIZE("_connectSSL.end");
|
||||||
|
#ifdef ESP8266
|
||||||
_max_thunkstack_use = stack_thunk_light_get_max_usage();
|
_max_thunkstack_use = stack_thunk_light_get_max_usage();
|
||||||
stack_thunk_light_del_ref();
|
stack_thunk_light_del_ref();
|
||||||
//stack_thunk_light_repaint();
|
//stack_thunk_light_repaint();
|
||||||
LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
|
LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
|
||||||
|
#endif // ESP8266
|
||||||
|
|
||||||
#ifdef USE_MQTT_TLS_CA_CERT
|
#ifdef USE_MQTT_TLS_CA_CERT
|
||||||
free(x509_minimal);
|
free(x509_minimal);
|
||||||
@ -982,7 +1023,9 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
|
|||||||
// if we arrived here, this means we had an OOM error, cleaning up
|
// if we arrived here, this means we had an OOM error, cleaning up
|
||||||
setLastError(ERR_OOM);
|
setLastError(ERR_OOM);
|
||||||
DEBUG_BSSL("_connectSSL: Out of memory\n");
|
DEBUG_BSSL("_connectSSL: Out of memory\n");
|
||||||
|
#ifdef ESP8266
|
||||||
stack_thunk_light_del_ref();
|
stack_thunk_light_del_ref();
|
||||||
|
#endif
|
||||||
#ifdef USE_MQTT_TLS_CA_CERT
|
#ifdef USE_MQTT_TLS_CA_CERT
|
||||||
free(x509_minimal);
|
free(x509_minimal);
|
||||||
#else
|
#else
|
||||||
|
@ -43,7 +43,11 @@ class WiFiClientSecure_light : public WiFiClient {
|
|||||||
|
|
||||||
uint8_t connected() override;
|
uint8_t connected() override;
|
||||||
size_t write(const uint8_t *buf, size_t size) override;
|
size_t write(const uint8_t *buf, size_t size) override;
|
||||||
|
#ifdef ESP8266
|
||||||
size_t write_P(PGM_P buf, size_t size) override;
|
size_t write_P(PGM_P buf, size_t size) override;
|
||||||
|
#else
|
||||||
|
size_t write_P(PGM_P buf, size_t size);
|
||||||
|
#endif
|
||||||
size_t write(const char *buf) {
|
size_t write(const char *buf) {
|
||||||
return write((const uint8_t*)buf, strlen(buf));
|
return write((const uint8_t*)buf, strlen(buf));
|
||||||
}
|
}
|
||||||
@ -55,11 +59,17 @@ class WiFiClientSecure_light : public WiFiClient {
|
|||||||
int available() override;
|
int available() override;
|
||||||
int read() override;
|
int read() override;
|
||||||
int peek() override;
|
int peek() override;
|
||||||
|
#ifdef ESP8266
|
||||||
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||||
bool flush(unsigned int maxWaitMs);
|
bool flush(unsigned int maxWaitMs);
|
||||||
bool stop(unsigned int maxWaitMs);
|
bool stop(unsigned int maxWaitMs);
|
||||||
void flush() override { (void)flush(0); }
|
void flush() override { (void)flush(0); }
|
||||||
void stop() override { (void)stop(0); }
|
void stop() override { (void)stop(0); }
|
||||||
|
#else
|
||||||
|
size_t peekBytes(uint8_t *buffer, size_t length);
|
||||||
|
void flush() override;
|
||||||
|
void stop() override;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Only check SHA1 fingerprint of public key
|
// Only check SHA1 fingerprint of public key
|
||||||
void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
|
void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
|
||||||
|
@ -680,7 +680,7 @@
|
|||||||
#define D_LOG_KNX "KNX: "
|
#define D_LOG_KNX "KNX: "
|
||||||
#define D_LOG_LOG "LOG: " // Logging
|
#define D_LOG_LOG "LOG: " // Logging
|
||||||
#define D_LOG_MODULE "MOD: " // Module
|
#define D_LOG_MODULE "MOD: " // Module
|
||||||
#define D_LOG_MDNS "DNS: " // mDNS
|
#define D_LOG_MDNS "mDN: " // mDNS
|
||||||
#define D_LOG_MQTT "MQT: " // MQTT
|
#define D_LOG_MQTT "MQT: " // MQTT
|
||||||
#define D_LOG_OTHER "OTH: " // Other
|
#define D_LOG_OTHER "OTH: " // Other
|
||||||
#define D_LOG_RESULT "RSL: " // Result
|
#define D_LOG_RESULT "RSL: " // Result
|
||||||
|
@ -73,7 +73,7 @@
|
|||||||
#define D_COMMAND "Befehl"
|
#define D_COMMAND "Befehl"
|
||||||
#define D_CONNECTED "verbunden"
|
#define D_CONNECTED "verbunden"
|
||||||
#define D_CORS_DOMAIN "CORS Domain"
|
#define D_CORS_DOMAIN "CORS Domain"
|
||||||
#define D_COUNT "zählen"
|
#define D_COUNT "Anzahl" // used as a noun throughout
|
||||||
#define D_COUNTER "Zähler"
|
#define D_COUNTER "Zähler"
|
||||||
#define D_CT_POWER "CT Power"
|
#define D_CT_POWER "CT Power"
|
||||||
#define D_CURRENT "Strom" // As in Voltage and Current
|
#define D_CURRENT "Strom" // As in Voltage and Current
|
||||||
@ -143,8 +143,8 @@
|
|||||||
#define D_POWERUSAGE_REACTIVE "Blindleistung"
|
#define D_POWERUSAGE_REACTIVE "Blindleistung"
|
||||||
#define D_PRESSURE "Luftdruck"
|
#define D_PRESSURE "Luftdruck"
|
||||||
#define D_PRESSUREATSEALEVEL "Luftdruck auf Meereshöhe"
|
#define D_PRESSUREATSEALEVEL "Luftdruck auf Meereshöhe"
|
||||||
#define D_PROGRAM_FLASH_SIZE "Ges. Flash Speicher"
|
#define D_PROGRAM_FLASH_SIZE "Flash nutzbar"
|
||||||
#define D_PROGRAM_SIZE "Ben. Flash Speicher"
|
#define D_PROGRAM_SIZE "Größe Programm"
|
||||||
#define D_PROJECT "Projekt"
|
#define D_PROJECT "Projekt"
|
||||||
#define D_RAIN "Regen"
|
#define D_RAIN "Regen"
|
||||||
#define D_RANGE "Bereich"
|
#define D_RANGE "Bereich"
|
||||||
@ -333,7 +333,7 @@
|
|||||||
#define D_PROGRAM_VERSION "Tasmota Version"
|
#define D_PROGRAM_VERSION "Tasmota Version"
|
||||||
#define D_BUILD_DATE_AND_TIME "Build-Datum & -Uhrzeit"
|
#define D_BUILD_DATE_AND_TIME "Build-Datum & -Uhrzeit"
|
||||||
#define D_CORE_AND_SDK_VERSION "Core-/SDK-Version"
|
#define D_CORE_AND_SDK_VERSION "Core-/SDK-Version"
|
||||||
#define D_FLASH_WRITE_COUNT "Anz. Flash Schreibzugriffe"
|
#define D_FLASH_WRITE_COUNT "Anz. Flash-Schreibzyklen"
|
||||||
#define D_MAC_ADDRESS "MAC-Adresse"
|
#define D_MAC_ADDRESS "MAC-Adresse"
|
||||||
#define D_MQTT_HOST "MQTT Host"
|
#define D_MQTT_HOST "MQTT Host"
|
||||||
#define D_MQTT_PORT "MQTT Port"
|
#define D_MQTT_PORT "MQTT Port"
|
||||||
@ -343,12 +343,12 @@
|
|||||||
#define D_MQTT_GROUP_TOPIC "MQTT Group Topic"
|
#define D_MQTT_GROUP_TOPIC "MQTT Group Topic"
|
||||||
#define D_MQTT_FULL_TOPIC "MQTT Full Topic"
|
#define D_MQTT_FULL_TOPIC "MQTT Full Topic"
|
||||||
#define D_MQTT_NO_RETAIN "MQTT No Retain"
|
#define D_MQTT_NO_RETAIN "MQTT No Retain"
|
||||||
#define D_MDNS_DISCOVERY "mDNS-Ermittlung"
|
#define D_MDNS_DISCOVERY "mDNS-Erkennung"
|
||||||
#define D_MDNS_ADVERTISE "mDNS-Bekanntmachung"
|
#define D_MDNS_ADVERTISE "mDNS-Freigaben"
|
||||||
#define D_ESP_CHIP_ID "ESP Chip ID"
|
#define D_ESP_CHIP_ID "ESP Chip ID"
|
||||||
#define D_FLASH_CHIP_ID "Flash Chip ID"
|
#define D_FLASH_CHIP_ID "Flash Chip ID"
|
||||||
#define D_FLASH_CHIP_SIZE "Realer Flash Speicher"
|
#define D_FLASH_CHIP_SIZE "Größe Flash-Chip"
|
||||||
#define D_FREE_PROGRAM_SPACE "Verf. Flash Speicher"
|
#define D_FREE_PROGRAM_SPACE "Flash frei"
|
||||||
|
|
||||||
#define D_UPGRADE_BY_WEBSERVER "Update über Web-Server"
|
#define D_UPGRADE_BY_WEBSERVER "Update über Web-Server"
|
||||||
#define D_OTA_URL "OTA-URL"
|
#define D_OTA_URL "OTA-URL"
|
||||||
|
@ -828,10 +828,10 @@
|
|||||||
#define THERMOSTAT_TEMP_BAND_NO_PEAK_DET 1 // Default temperature band in thenths of degrees celsius within no peak will be detected
|
#define THERMOSTAT_TEMP_BAND_NO_PEAK_DET 1 // Default temperature band in thenths of degrees celsius within no peak will be detected
|
||||||
#define THERMOSTAT_TIME_STD_DEV_PEAK_DET_OK 10 // Default standard deviation in minutes of the oscillation periods within the peak detection is successful
|
#define THERMOSTAT_TIME_STD_DEV_PEAK_DET_OK 10 // Default standard deviation in minutes of the oscillation periods within the peak detection is successful
|
||||||
|
|
||||||
// -- PID and Timeprop ------------------------------
|
// -- PID and Timeprop ------------------------------ // Both together will add +12k1 code
|
||||||
//#define USE_TIMEPROP // Add support for the timeprop feature (+0k8 code)
|
// #define use TIMEPROP // Add support for the timeprop feature (+9k1 code)
|
||||||
// For details on the configuration please see the header of tasmota/xdrv_48_timeprop.ino
|
// For details on the configuration please see the header of tasmota/xdrv_48_timeprop.ino
|
||||||
//#define USE_PID // Add suport for the PID feature (+11k1 code)
|
// #define USE_PID // Add suport for the PID feature (+11k2 code)
|
||||||
// For details on the configuration please see the header of tasmota/xdrv_49_pid.ino
|
// For details on the configuration please see the header of tasmota/xdrv_49_pid.ino
|
||||||
// -- End of general directives ---------------------
|
// -- End of general directives ---------------------
|
||||||
|
|
||||||
|
@ -154,19 +154,20 @@ bool RtcRebootValid(void)
|
|||||||
* 0x000xxxxx - Unzipped binary code end
|
* 0x000xxxxx - Unzipped binary code end
|
||||||
* 0x000x1000 - First page used by Core OTA
|
* 0x000x1000 - First page used by Core OTA
|
||||||
* ::::
|
* ::::
|
||||||
* 0x000F2FFF
|
* 0x000F2FFF 0x000F5FFF 0x000F5FFF
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Next 32k is overwritten by OTA
|
* Next 32k is overwritten by OTA
|
||||||
* 0x000F3000 - 4k Tasmota Quick Power Cycle counter (SETTINGS_LOCATION - CFG_ROTATES) - First four bytes only
|
* 0x000F3000 0x000F6000 0x000F6000 - 4k Tasmota Quick Power Cycle counter (SETTINGS_LOCATION - CFG_ROTATES) - First four bytes only
|
||||||
* 0x000F3FFF
|
* 0x000F3FFF 0x000F6FFF 0x000F6FFF
|
||||||
* 0x000F4000 - 4k First Tasmota rotating settings page
|
* 0x000F4000 0x000F7000 0x000F7000 - 4k First Tasmota rotating settings page
|
||||||
* ::::
|
* ::::
|
||||||
* 0x000FA000 - 4k Last Tasmota rotating settings page = Last page used by Core OTA (SETTINGS_LOCATION)
|
* 0x000FA000 0x000FD000 0x000FD000 - 4k Last Tasmota rotating settings page = Last page used by Core OTA (SETTINGS_LOCATION)
|
||||||
* 0x000FAFFF
|
* 0x000FAFFF 0x000FDFFF 0x000FDFFF
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* 0x000FB000 0x000FB000 - 15k9 Not used
|
* 0x000FE000 0x000FE000 - 3k9 Not used
|
||||||
* 0x000FEFF0 0x000FEFF0 - 4k1 Empty
|
* 0x000FEFF0 0x000FEFF0 - 4k1 Empty
|
||||||
* 0x000FFFFF 0x000FFFFF
|
* 0x000FFFFF 0x000FFFFF
|
||||||
|
*
|
||||||
* 0x000FB000 0x00100000 0x00100000 - 0k, 980k or 2980k Core FS start (LittleFS)
|
* 0x000FB000 0x00100000 0x00100000 - 0k, 980k or 2980k Core FS start (LittleFS)
|
||||||
* 0x000FB000 0x001FA000 0x003FA000 - 0k, 980k or 2980k Core FS end (LittleFS)
|
* 0x000FB000 0x001FA000 0x003FA000 - 0k, 980k or 2980k Core FS end (LittleFS)
|
||||||
* 0x001FAFFF 0x003FAFFF
|
* 0x001FAFFF 0x003FAFFF
|
||||||
@ -189,7 +190,8 @@ extern "C" {
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
|
|
||||||
extern "C" uint32_t _FS_start; // 1M = 0x402fb000, 2M = 0x40300000, 4M = 0x40300000
|
extern "C" uint32_t _FS_start; // 1M = 0x402fb000, 2M = 0x40300000, 4M = 0x40300000
|
||||||
uint32_t SETTINGS_LOCATION = (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE) -1; // 0xFA, 0xFF or 0xFF
|
const uint32_t FLASH_FS_START = (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE);
|
||||||
|
uint32_t SETTINGS_LOCATION = FLASH_FS_START -1; // 0xFA, 0x0FF or 0x0FF
|
||||||
|
|
||||||
// From libraries/EEPROM/EEPROM.cpp EEPROMClass
|
// From libraries/EEPROM/EEPROM.cpp EEPROMClass
|
||||||
extern "C" uint32_t _EEPROM_start; // 1M = 0x402FB000, 2M = 0x403FB000, 4M = 0x405FB000
|
extern "C" uint32_t _EEPROM_start; // 1M = 0x402FB000, 2M = 0x403FB000, 4M = 0x405FB000
|
||||||
@ -205,14 +207,16 @@ uint32_t SETTINGS_LOCATION = FLASH_EEPROM_START;
|
|||||||
|
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
|
|
||||||
const uint8_t CFG_ROTATES = 7; // Number of flash sectors used (handles uploads)
|
const uint8_t CFG_ROTATES = 7; // Number of flash sectors used (handles uploads)
|
||||||
|
|
||||||
uint32_t settings_location = FLASH_EEPROM_START;
|
uint32_t settings_location = FLASH_EEPROM_START;
|
||||||
uint32_t settings_crc32 = 0;
|
uint32_t settings_crc32 = 0;
|
||||||
uint8_t *settings_buffer = nullptr;
|
uint8_t *settings_buffer = nullptr;
|
||||||
|
|
||||||
void SettingsInit(void) {
|
void SettingsInit(void) {
|
||||||
if (SETTINGS_LOCATION > 0xFA) { SETTINGS_LOCATION = 0xFA; } // Skip empty partition part
|
if (SETTINGS_LOCATION > 0xFA) {
|
||||||
|
SETTINGS_LOCATION = 0xFD; // Skip empty partition part and keep in first 1M
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
@ -534,6 +538,9 @@ void SettingsSave(uint8_t rotate)
|
|||||||
Settings.cfg_crc32 = GetSettingsCrc32();
|
Settings.cfg_crc32 = GetSettingsCrc32();
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
|
#ifdef USE_UFILESYS
|
||||||
|
TfsSaveFile(TASM_FILE_SETTINGS, (const uint8_t*)&Settings, sizeof(Settings));
|
||||||
|
#endif // USE_UFILESYS
|
||||||
if (ESP.flashEraseSector(settings_location)) {
|
if (ESP.flashEraseSector(settings_location)) {
|
||||||
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
||||||
}
|
}
|
||||||
@ -559,39 +566,66 @@ void SettingsSave(uint8_t rotate)
|
|||||||
|
|
||||||
void SettingsLoad(void) {
|
void SettingsLoad(void) {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
// Load configuration from eeprom or one of 7 slots below if first valid load does not stop_flash_rotate
|
// Load configuration from optional file and flash (eeprom and 7 additonal slots) if first valid load does not stop_flash_rotate
|
||||||
// Activated with version 8.4.0.2 - Fails to read any config before version 6.6.0.11
|
// Activated with version 8.4.0.2 - Fails to read any config before version 6.6.0.11
|
||||||
settings_location = 0;
|
settings_location = 0;
|
||||||
uint32_t save_flag = 0;
|
uint32_t save_flag = 0;
|
||||||
uint32_t flash_location = FLASH_EEPROM_START;
|
uint32_t max_slots = CFG_ROTATES +1;
|
||||||
for (uint32_t i = 0; i < CFG_ROTATES; i++) { // Read all config pages in search of valid and latest
|
uint32_t flash_location;
|
||||||
if (1 == i) { flash_location = SETTINGS_LOCATION; }
|
uint32_t slot = 1;
|
||||||
ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
#ifdef USE_UFILESYS
|
||||||
|
if (TfsLoadFile(TASM_FILE_SETTINGS, (uint8_t*)&Settings, sizeof(Settings))) {
|
||||||
|
flash_location = 1;
|
||||||
|
slot = 0;
|
||||||
|
}
|
||||||
|
#endif // USE_UFILESYS
|
||||||
|
while (slot <= max_slots) { // Read all config pages in search of valid and latest
|
||||||
|
if (slot > 0) {
|
||||||
|
flash_location = (1 == slot) ? FLASH_EEPROM_START : (2 == slot) ? SETTINGS_LOCATION : flash_location -1;
|
||||||
|
ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
||||||
|
}
|
||||||
if ((Settings.cfg_crc32 != 0xFFFFFFFF) && (Settings.cfg_crc32 != 0x00000000) && (Settings.cfg_crc32 == GetSettingsCrc32())) {
|
if ((Settings.cfg_crc32 != 0xFFFFFFFF) && (Settings.cfg_crc32 != 0x00000000) && (Settings.cfg_crc32 == GetSettingsCrc32())) {
|
||||||
if (Settings.save_flag > save_flag) { // Find latest page based on incrementing save_flag
|
if (Settings.save_flag > save_flag) { // Find latest page based on incrementing save_flag
|
||||||
save_flag = Settings.save_flag;
|
save_flag = Settings.save_flag;
|
||||||
settings_location = flash_location;
|
settings_location = flash_location;
|
||||||
if (Settings.flag.stop_flash_rotate && (0 == i)) { // Stop if only eeprom area should be used and it is valid
|
if (Settings.flag.stop_flash_rotate && (1 == slot)) { // Stop if only eeprom area should be used and it is valid
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flash_location--;
|
slot++;
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
if (settings_location > 0) {
|
if (settings_location > 0) {
|
||||||
ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
#ifdef USE_UFILESYS
|
||||||
AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings.save_flag);
|
if (1 == settings_location) {
|
||||||
|
TfsLoadFile(TASM_FILE_SETTINGS, (uint8_t*)&Settings, sizeof(Settings));
|
||||||
|
AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from File, " D_COUNT " %lu"), Settings.save_flag);
|
||||||
|
} else
|
||||||
|
#endif // USE_UFILESYS
|
||||||
|
{
|
||||||
|
ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
||||||
|
AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings.save_flag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
uint32_t source = SettingsRead(&Settings, sizeof(Settings));
|
uint32_t source = SettingsRead(&Settings, sizeof(Settings));
|
||||||
|
if (source) { settings_location = 1; }
|
||||||
AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from %s, " D_COUNT " %lu"), (source)?"File":"Nvm", Settings.save_flag);
|
AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from %s, " D_COUNT " %lu"), (source)?"File":"Nvm", Settings.save_flag);
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
|
|
||||||
#ifndef FIRMWARE_MINIMAL
|
#ifndef FIRMWARE_MINIMAL
|
||||||
if ((0 == settings_location) || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h
|
if ((0 == settings_location) || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h
|
||||||
SettingsDefault();
|
#ifdef USE_UFILESYS
|
||||||
|
if (TfsLoadFile(TASM_FILE_SETTINGS_LKG, (uint8_t*)&Settings, sizeof(Settings)) && (Settings.cfg_crc32 == GetSettingsCrc32())) {
|
||||||
|
settings_location = 1;
|
||||||
|
AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from LKG File, " D_COUNT " %lu"), Settings.save_flag);
|
||||||
|
} else
|
||||||
|
#endif // USE_UFILESYS
|
||||||
|
{
|
||||||
|
SettingsDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
settings_crc32 = GetSettingsCrc32();
|
settings_crc32 = GetSettingsCrc32();
|
||||||
#endif // FIRMWARE_MINIMAL
|
#endif // FIRMWARE_MINIMAL
|
||||||
@ -604,25 +638,6 @@ uint32_t CfgTime(void) {
|
|||||||
return Settings.cfg_timestamp;
|
return Settings.cfg_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EspErase(uint32_t start_sector, uint32_t end_sector)
|
|
||||||
{
|
|
||||||
bool serial_output = (LOG_LEVEL_DEBUG_MORE <= TasmotaGlobal.seriallog_level);
|
|
||||||
for (uint32_t sector = start_sector; sector < end_sector; sector++) {
|
|
||||||
|
|
||||||
bool result = ESP.flashEraseSector(sector); // Arduino core - erases flash as seen by SDK
|
|
||||||
// bool result = !SPIEraseSector(sector); // SDK - erases flash as seen by SDK
|
|
||||||
// bool result = EsptoolEraseSector(sector); // Esptool - erases flash completely (slow)
|
|
||||||
|
|
||||||
if (serial_output) {
|
|
||||||
Serial.printf_P(PSTR(D_LOG_APPLICATION D_ERASED_SECTOR " %d %s\n"), sector, (result) ? D_OK : D_ERROR);
|
|
||||||
delay(10);
|
|
||||||
} else {
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
OsWatchLoop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void SettingsErase(uint8_t type)
|
void SettingsErase(uint8_t type)
|
||||||
{
|
{
|
||||||
@ -635,54 +650,52 @@ void SettingsErase(uint8_t type)
|
|||||||
|
|
||||||
The default erase function is EspTool (EsptoolErase)
|
The default erase function is EspTool (EsptoolErase)
|
||||||
|
|
||||||
0 = Erase from program end until end of flash as seen by SDK
|
0 = Erase from program end until end of flash as seen by SDK including optional filesystem
|
||||||
1 = Erase 16k SDK parameter area near end of flash as seen by SDK (0x0xFCxxx - 0x0xFFFFF) solving possible wifi errors
|
1 = Erase 16k SDK parameter area near end of flash as seen by SDK (0x0XFCxxx - 0x0XFFFFF) solving possible wifi errors
|
||||||
2 = Erase Tasmota parameter area (0x0xF3xxx - 0x0xFBFFF)
|
2 = Erase from program end until end of flash as seen by SDK excluding optional filesystem
|
||||||
3 = Erase Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
3 = Erase Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
||||||
4 = Erase SDK parameter area used for wifi calibration (0x0FCxxx - 0x0FCFFF)
|
4 = Erase SDK parameter area used for wifi calibration (0x0FCxxx - 0x0FCFFF)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FIRMWARE_MINIMAL
|
#ifndef FIRMWARE_MINIMAL
|
||||||
|
// Reset 2 = Erase all flash from program end to end of physical flash
|
||||||
uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1;
|
uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1;
|
||||||
uint32_t _sectorEnd = ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE; // Flash size as reported by hardware
|
uint32_t _sectorEnd = ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE; // Flash size as reported by hardware
|
||||||
if (1 == type) {
|
if (1 == type) { // Reset 3 = SDK parameter area
|
||||||
// source Esp.cpp and core_esp8266_phy.cpp
|
// source Esp.cpp and core_esp8266_phy.cpp
|
||||||
_sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4; // SDK parameter area
|
_sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4;
|
||||||
}
|
|
||||||
else if (2 == type) {
|
|
||||||
_sectorStart = SETTINGS_LOCATION - CFG_ROTATES; // Tasmota parameter area (0x0F3xxx - 0x0FAFFF)
|
|
||||||
_sectorEnd = SETTINGS_LOCATION;
|
|
||||||
}
|
|
||||||
else if (3 == type) {
|
|
||||||
_sectorStart = SETTINGS_LOCATION - CFG_ROTATES; // Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
|
||||||
_sectorEnd = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; // Flash size as seen by SDK
|
|
||||||
}
|
|
||||||
else if (4 == type) {
|
|
||||||
// _sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4; // SDK phy area and Core calibration sector (0x0FC000)
|
|
||||||
_sectorStart = FLASH_EEPROM_START +1; // SDK phy area and Core calibration sector (0x0FC000)
|
|
||||||
_sectorEnd = _sectorStart +1; // SDK end of phy area and Core calibration sector (0x0FCFFF)
|
|
||||||
}
|
}
|
||||||
|
else if (2 == type) { // Reset 5, 6 = Erase all flash from program end to end of physical flash but skip filesystem
|
||||||
/*
|
/*
|
||||||
else if (5 == type) {
|
#ifdef USE_UFILESYS
|
||||||
_sectorStart = (ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE) -4; // SDK phy area and Core calibration sector (0xxFC000)
|
TfsDeleteFile(TASM_FILE_SETTINGS); // Not needed as it is recreated by set defaults before restart
|
||||||
_sectorEnd = _sectorStart +1; // SDK end of phy area and Core calibration sector (0xxFCFFF)
|
#endif
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
else {
|
EsptoolErase(_sectorStart, FLASH_FS_START);
|
||||||
return;
|
_sectorStart = FLASH_EEPROM_START;
|
||||||
|
_sectorEnd = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; // Flash size as seen by SDK
|
||||||
|
}
|
||||||
|
else if (3 == type) { // QPC Reached = QPC and Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
||||||
|
#ifdef USE_UFILESYS
|
||||||
|
TfsDeleteFile(TASM_FILE_SETTINGS);
|
||||||
|
#endif
|
||||||
|
EsptoolErase(SETTINGS_LOCATION - CFG_ROTATES, SETTINGS_LOCATION +1);
|
||||||
|
_sectorStart = FLASH_EEPROM_START;
|
||||||
|
_sectorEnd = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; // Flash size as seen by SDK
|
||||||
|
}
|
||||||
|
else if (4 == type) { // WIFI_FORCE_RF_CAL_ERASE = SDK wifi calibration
|
||||||
|
_sectorStart = FLASH_EEPROM_START +1; // SDK phy area and Core calibration sector (0x0XFC000)
|
||||||
|
_sectorEnd = _sectorStart +1; // SDK end of phy area and Core calibration sector (0x0XFCFFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " from 0x%08X to 0x%08X"), _sectorStart * SPI_FLASH_SEC_SIZE, (_sectorEnd * SPI_FLASH_SEC_SIZE) -1);
|
EsptoolErase(_sectorStart, _sectorEnd); // Esptool - erases flash completely
|
||||||
|
|
||||||
// EspErase(_sectorStart, _sectorEnd); // Arduino core and SDK - erases flash as seen by SDK
|
|
||||||
EsptoolErase(_sectorStart, _sectorEnd); // Esptool - erases flash completely
|
|
||||||
#endif // FIRMWARE_MINIMAL
|
#endif // FIRMWARE_MINIMAL
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
|
|
||||||
void SettingsSdkErase(void)
|
void SettingsSdkErase(void)
|
||||||
{
|
{
|
||||||
WiFi.disconnect(false); // Delete SDK wifi config
|
WiFi.disconnect(false); // Delete SDK wifi config
|
||||||
SettingsErase(1);
|
SettingsErase(1);
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
@ -727,12 +727,12 @@ void CmndRestart(void)
|
|||||||
switch (XdrvMailbox.payload) {
|
switch (XdrvMailbox.payload) {
|
||||||
case 1:
|
case 1:
|
||||||
TasmotaGlobal.restart_flag = 2;
|
TasmotaGlobal.restart_flag = 2;
|
||||||
ResponseCmndChar(D_JSON_RESTARTING);
|
ResponseCmndChar(PSTR(D_JSON_RESTARTING));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
TasmotaGlobal.restart_flag = 2;
|
TasmotaGlobal.restart_flag = 2;
|
||||||
TasmotaGlobal.restart_halt = true;
|
TasmotaGlobal.restart_halt = true;
|
||||||
ResponseCmndChar(D_JSON_HALTING);
|
ResponseCmndChar(PSTR(D_JSON_HALTING));
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
CmndCrash(); // force a crash
|
CmndCrash(); // force a crash
|
||||||
@ -967,8 +967,9 @@ void CmndSetoption(void)
|
|||||||
bitWrite(Settings.flag5.data, pindex, XdrvMailbox.payload);
|
bitWrite(Settings.flag5.data, pindex, XdrvMailbox.payload);
|
||||||
switch (pindex) {
|
switch (pindex) {
|
||||||
case 1: // SetOption115 - Enable ESP32 MI32
|
case 1: // SetOption115 - Enable ESP32 MI32
|
||||||
Settings.flag3.sleep_normal = 1; // SetOption60 - Enable normal sleep instead of dynamic sleep
|
if (0 == XdrvMailbox.payload) {
|
||||||
TasmotaGlobal.restart_flag = 2;
|
TasmotaGlobal.restart_flag = 2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1208,7 +1209,7 @@ void CmndGpio(void)
|
|||||||
if (jsflg2) {
|
if (jsflg2) {
|
||||||
ResponseClear();
|
ResponseClear();
|
||||||
} else {
|
} else {
|
||||||
ResponseCmndChar(D_JSON_NOT_SUPPORTED);
|
ResponseCmndChar(PSTR(D_JSON_NOT_SUPPORTED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,30 +138,26 @@ int32_t NvmErase(const char *sNvsName) {
|
|||||||
|
|
||||||
void SettingsErase(uint8_t type) {
|
void SettingsErase(uint8_t type) {
|
||||||
// SDK and Tasmota data is held in default NVS partition
|
// SDK and Tasmota data is held in default NVS partition
|
||||||
// Tasmota data is held also in file /settings on default filesystem
|
// Tasmota data is held also in file /.settings on default filesystem
|
||||||
// cal_data - SDK PHY calibration data as documented in esp_phy_init.h
|
// cal_data - SDK PHY calibration data as documented in esp_phy_init.h
|
||||||
// qpc - Tasmota Quick Power Cycle state
|
// qpc - Tasmota Quick Power Cycle state
|
||||||
// main - Tasmota Settings data
|
// main - Tasmota Settings data
|
||||||
int32_t r1, r2, r3;
|
int32_t r1, r2, r3;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0: // Reset 2, 5, 6 = Erase all flash from program end to end of physical flash
|
case 0: // Reset 2 = Erase all flash from program end to end of physical flash
|
||||||
|
case 2: // Reset 5, 6 = Erase all flash from program end to end of physical flash excluding filesystem
|
||||||
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
|
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
|
||||||
r1 = NvmErase("qpc");
|
r1 = NvmErase("qpc");
|
||||||
r2 = NvmErase("main");
|
r2 = NvmErase("main");
|
||||||
r3 = TfsDeleteFile(TASM_FILE_SETTINGS);
|
r3 = TfsDeleteFile(TASM_FILE_SETTINGS);
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " Tasmota data (%d,%d,%d)"), r1, r2, r3);
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " Tasmota data (%d,%d,%d)"), r1, r2, r3);
|
||||||
break;
|
break;
|
||||||
case 1: case 4: // Reset 3 or WIFI_FORCE_RF_CAL_ERASE = SDK parameter area
|
case 1: // Reset 3 = SDK parameter area
|
||||||
|
case 4: // WIFI_FORCE_RF_CAL_ERASE = SDK parameter area
|
||||||
r1 = esp_phy_erase_cal_data_in_nvs();
|
r1 = esp_phy_erase_cal_data_in_nvs();
|
||||||
// r1 = NvmErase("cal_data");
|
// r1 = NvmErase("cal_data");
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " PHY data (%d)"), r1);
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " PHY data (%d)"), r1);
|
||||||
break;
|
break;
|
||||||
case 2: // Not used = QPC and Tasmota parameter area (0x0F3xxx - 0x0FBFFF)
|
|
||||||
r1 = NvmErase("qpc");
|
|
||||||
r2 = NvmErase("main");
|
|
||||||
r3 = TfsDeleteFile(TASM_FILE_SETTINGS);
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " Tasmota data (%d,%d,%d)"), r1, r2, r3);
|
|
||||||
break;
|
|
||||||
case 3: // QPC Reached = QPC, Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
case 3: // QPC Reached = QPC, Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
||||||
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
|
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
|
||||||
r1 = NvmErase("qpc");
|
r1 = NvmErase("qpc");
|
||||||
|
@ -95,6 +95,8 @@ bool EsptoolEraseSector(uint32_t sector)
|
|||||||
|
|
||||||
void EsptoolErase(uint32_t start_sector, uint32_t end_sector)
|
void EsptoolErase(uint32_t start_sector, uint32_t end_sector)
|
||||||
{
|
{
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " from 0x%08X to 0x%08X"), start_sector * SPI_FLASH_SEC_SIZE, (end_sector * SPI_FLASH_SEC_SIZE) -1);
|
||||||
|
|
||||||
int next_erase_sector = start_sector;
|
int next_erase_sector = start_sector;
|
||||||
int remaining_erase_sector = end_sector - start_sector;
|
int remaining_erase_sector = end_sector - start_sector;
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ void StartMdns(void) {
|
|||||||
// mdns_delayed_start--;
|
// mdns_delayed_start--;
|
||||||
// } else {
|
// } else {
|
||||||
// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
|
// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
|
||||||
|
MDNS.end(); // close existing or MDNS.begin will fail
|
||||||
Mdns.begun = (uint8_t)MDNS.begin(TasmotaGlobal.hostname);
|
Mdns.begun = (uint8_t)MDNS.begin(TasmotaGlobal.hostname);
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Mdns.begun) ? D_INITIALIZED : D_FAILED);
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Mdns.begun) ? D_INITIALIZED : D_FAILED);
|
||||||
// }
|
// }
|
||||||
|
@ -455,16 +455,13 @@ void RtcSecond(void)
|
|||||||
Rtc.midnight_now = true;
|
Rtc.midnight_now = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
if (mutex) { // Time is just synced and is valid
|
if (mutex) { // Time is just synced and is valid
|
||||||
// Sync RTOS time to be used by SD Card time stamps
|
// Sync Core/RTOS time to be used by file system time stamps
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = Rtc.local_time;
|
tv.tv_sec = Rtc.local_time;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
settimeofday(&tv, nullptr);
|
settimeofday(&tv, nullptr);
|
||||||
}
|
}
|
||||||
#endif // ESP32
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RtcTime.year += 1970;
|
RtcTime.year += 1970;
|
||||||
|
@ -886,6 +886,15 @@ void PerformEverySecond(void)
|
|||||||
ESP_getSketchSize(); // Init sketchsize as it can take up to 2 seconds
|
ESP_getSketchSize(); // Init sketchsize as it can take up to 2 seconds
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_UFILESYS
|
||||||
|
static bool settings_lkg = false; // Settings saved as Last Known Good
|
||||||
|
// Copy Settings as Last Known Good if no changes have been saved since 30 minutes
|
||||||
|
if (!settings_lkg && (UtcTime() > START_VALID_TIME) && (Settings.cfg_timestamp < UtcTime() - (30 * 60))) {
|
||||||
|
TfsSaveFile(TASM_FILE_SETTINGS_LKG, (const uint8_t*)&Settings, sizeof(Settings));
|
||||||
|
settings_lkg = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------------------------*\
|
||||||
@ -1134,7 +1143,7 @@ void Every250mSeconds(void)
|
|||||||
// Backup mqtt host, port, client, username and password
|
// Backup mqtt host, port, client, username and password
|
||||||
// }
|
// }
|
||||||
if ((215 == TasmotaGlobal.restart_flag) || (216 == TasmotaGlobal.restart_flag)) {
|
if ((215 == TasmotaGlobal.restart_flag) || (216 == TasmotaGlobal.restart_flag)) {
|
||||||
SettingsErase(0); // Erase all flash from program end to end of physical flash
|
SettingsErase(2); // Erase all flash from program end to end of physical excluding optional filesystem
|
||||||
}
|
}
|
||||||
SettingsDefault();
|
SettingsDefault();
|
||||||
// Restore current SSIDs and Passwords
|
// Restore current SSIDs and Passwords
|
||||||
@ -1169,7 +1178,7 @@ void Every250mSeconds(void)
|
|||||||
}
|
}
|
||||||
TasmotaGlobal.restart_flag--;
|
TasmotaGlobal.restart_flag--;
|
||||||
if (TasmotaGlobal.restart_flag <= 0) {
|
if (TasmotaGlobal.restart_flag <= 0) {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "%s"), (TasmotaGlobal.restart_halt) ? "Halted" : D_RESTARTING);
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "%s"), (TasmotaGlobal.restart_halt) ? PSTR("Halted") : PSTR(D_RESTARTING));
|
||||||
EspRestart();
|
EspRestart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1616,8 +1625,8 @@ void GpioInit(void)
|
|||||||
if (!TasmotaGlobal.soft_spi_enabled) {
|
if (!TasmotaGlobal.soft_spi_enabled) {
|
||||||
bool valid_cs = (ValidSpiPinUsed(GPIO_SPI_CS) ||
|
bool valid_cs = (ValidSpiPinUsed(GPIO_SPI_CS) ||
|
||||||
ValidSpiPinUsed(GPIO_RC522_CS) ||
|
ValidSpiPinUsed(GPIO_RC522_CS) ||
|
||||||
ValidSpiPinUsed(GPIO_NRF24_CS) ||
|
(ValidSpiPinUsed(GPIO_NRF24_CS) && ValidSpiPinUsed(GPIO_NRF24_DC)) ||
|
||||||
ValidSpiPinUsed(GPIO_ILI9341_CS) ||
|
(ValidSpiPinUsed(GPIO_ILI9341_CS) && ValidSpiPinUsed(GPIO_ILI9341_DC)) ||
|
||||||
ValidSpiPinUsed(GPIO_EPAPER29_CS) ||
|
ValidSpiPinUsed(GPIO_EPAPER29_CS) ||
|
||||||
ValidSpiPinUsed(GPIO_EPAPER42_CS) ||
|
ValidSpiPinUsed(GPIO_EPAPER42_CS) ||
|
||||||
ValidSpiPinUsed(GPIO_ILI9488_CS) ||
|
ValidSpiPinUsed(GPIO_ILI9488_CS) ||
|
||||||
@ -1625,17 +1634,11 @@ void GpioInit(void)
|
|||||||
ValidSpiPinUsed(GPIO_RA8876_CS) ||
|
ValidSpiPinUsed(GPIO_RA8876_CS) ||
|
||||||
ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too
|
ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too
|
||||||
ValidSpiPinUsed(GPIO_ST7789_CS) ||
|
ValidSpiPinUsed(GPIO_ST7789_CS) ||
|
||||||
ValidSpiPinUsed(GPIO_SSD1331_CS) ||
|
(ValidSpiPinUsed(GPIO_SSD1331_CS) && ValidSpiPinUsed(GPIO_SSD1331_DC)) ||
|
||||||
ValidSpiPinUsed(GPIO_SDCARD_CS)
|
ValidSpiPinUsed(GPIO_SDCARD_CS)
|
||||||
);
|
);
|
||||||
bool valid_dc = (ValidSpiPinUsed(GPIO_SPI_DC) ||
|
|
||||||
ValidSpiPinUsed(GPIO_NRF24_DC) ||
|
|
||||||
ValidSpiPinUsed(GPIO_ILI9341_DC) ||
|
|
||||||
ValidSpiPinUsed(GPIO_ST7789_DC) ||
|
|
||||||
ValidSpiPinUsed(GPIO_SSD1331_DC)
|
|
||||||
);
|
|
||||||
// If SPI_CS and/or SPI_DC is used they must be valid
|
// If SPI_CS and/or SPI_DC is used they must be valid
|
||||||
TasmotaGlobal.spi_enabled = (valid_cs && valid_dc) ? SPI_MOSI_MISO : SPI_NONE;
|
TasmotaGlobal.spi_enabled = (valid_cs) ? SPI_MOSI_MISO : SPI_NONE;
|
||||||
if (TasmotaGlobal.spi_enabled) {
|
if (TasmotaGlobal.spi_enabled) {
|
||||||
TasmotaGlobal.my_module.io[12] = AGPIO(GPIO_SPI_MISO);
|
TasmotaGlobal.my_module.io[12] = AGPIO(GPIO_SPI_MISO);
|
||||||
SetPin(12, AGPIO(GPIO_SPI_MISO));
|
SetPin(12, AGPIO(GPIO_SPI_MISO));
|
||||||
|
@ -32,7 +32,6 @@ IPAddress udp_remote_ip; // M-Search remote IP address
|
|||||||
uint16_t udp_remote_port; // M-Search remote port
|
uint16_t udp_remote_port; // M-Search remote port
|
||||||
|
|
||||||
bool udp_connected = false;
|
bool udp_connected = false;
|
||||||
bool udp_response_mutex = false; // M-Search response mutex to control re-entry
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#ifndef UDP_MAX_PACKETS
|
#ifndef UDP_MAX_PACKETS
|
||||||
@ -89,14 +88,12 @@ bool UdpConnect(void)
|
|||||||
if (UdpCtx.listen(&addr, 1900)) { // port 1900
|
if (UdpCtx.listen(&addr, 1900)) { // port 1900
|
||||||
// OK
|
// OK
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
||||||
udp_response_mutex = false;
|
|
||||||
udp_connected = true;
|
udp_connected = true;
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) {
|
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
||||||
udp_response_mutex = false;
|
|
||||||
udp_connected = true;
|
udp_connected = true;
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
}
|
}
|
||||||
@ -123,28 +120,29 @@ void PollUdp(void)
|
|||||||
packet->buf[packet->len] = 0; // add NULL at the end of the packet
|
packet->buf[packet->len] = 0; // add NULL at the end of the packet
|
||||||
char * packet_buffer = (char*) &packet->buf;
|
char * packet_buffer = (char*) &packet->buf;
|
||||||
int32_t len = packet->len;
|
int32_t len = packet->len;
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
while (PortUdp.parsePacket()) {
|
while (uint32_t pack_len = PortUdp.parsePacket()) {
|
||||||
char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet
|
char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet
|
||||||
|
|
||||||
int32_t len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1);
|
int32_t len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1);
|
||||||
packet_buffer[len] = 0;
|
packet_buffer[len] = 0;
|
||||||
|
PortUdp.flush();
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d/%d)"), len, pack_len);
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
|
|
||||||
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
|
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
|
||||||
|
|
||||||
// Simple Service Discovery Protocol (SSDP)
|
// Simple Service Discovery Protocol (SSDP)
|
||||||
if (Settings.flag2.emulation) {
|
if (Settings.flag2.emulation) {
|
||||||
#if defined(USE_SCRIPT_HUE) || defined(USE_ZIGBEE)
|
#if defined(USE_SCRIPT_HUE) || defined(USE_ZIGBEE)
|
||||||
if (!udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
if (TasmotaGlobal.devices_present && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
||||||
#else
|
#else
|
||||||
if (TasmotaGlobal.devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
if (TasmotaGlobal.devices_present && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
||||||
#endif
|
#endif
|
||||||
if (0 == udp_last_received) {
|
if (0 == udp_last_received) {
|
||||||
udp_last_received = millis();
|
udp_last_received = millis();
|
||||||
udp_response_mutex = true;
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
udp_remote_ip = packet->srcaddr;
|
udp_remote_ip = packet->srcaddr;
|
||||||
udp_remote_port = packet->srcport;
|
udp_remote_port = packet->srcport;
|
||||||
@ -159,35 +157,34 @@ void PollUdp(void)
|
|||||||
LowerCase(packet_buffer, packet_buffer);
|
LowerCase(packet_buffer, packet_buffer);
|
||||||
RemoveSpace(packet_buffer);
|
RemoveSpace(packet_buffer);
|
||||||
|
|
||||||
|
bool udp_proccessed = false; // make sure we process the packet only once
|
||||||
#ifdef USE_EMULATION_WEMO
|
#ifdef USE_EMULATION_WEMO
|
||||||
if (EMUL_WEMO == Settings.flag2.emulation) {
|
if (!udp_proccessed && (EMUL_WEMO == Settings.flag2.emulation)) {
|
||||||
if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's
|
if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's
|
||||||
WemoRespondToMSearch(1);
|
WemoRespondToMSearch(1);
|
||||||
return;
|
udp_proccessed = true;
|
||||||
}
|
}
|
||||||
else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus)
|
else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus)
|
||||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||||
WemoRespondToMSearch(2);
|
WemoRespondToMSearch(2);
|
||||||
return;
|
udp_proccessed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_EMULATION_WEMO
|
#endif // USE_EMULATION_WEMO
|
||||||
|
|
||||||
#ifdef USE_EMULATION_HUE
|
#ifdef USE_EMULATION_HUE
|
||||||
if (EMUL_HUE == Settings.flag2.emulation) {
|
if (!udp_proccessed && (EMUL_HUE == Settings.flag2.emulation)) {
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: HUE"));
|
||||||
if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) ||
|
if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) ||
|
||||||
(strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) ||
|
(strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) ||
|
||||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||||
HueRespondToMSearch();
|
HueRespondToMSearch();
|
||||||
return;
|
udp_proccessed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_EMULATION_HUE
|
#endif // USE_EMULATION_HUE
|
||||||
|
|
||||||
udp_response_mutex = false;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,11 +153,24 @@ void WiFiSetSleepMode(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Sleep explanation: https://github.com/esp8266/Arduino/blob/3f0c601cfe81439ce17e9bd5d28994a7ed144482/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L255
|
// Sleep explanation: https://github.com/esp8266/Arduino/blob/3f0c601cfe81439ce17e9bd5d28994a7ed144482/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L255
|
||||||
|
/*
|
||||||
if (TasmotaGlobal.sleep && Settings.flag3.sleep_normal) { // SetOption60 - Enable normal sleep instead of dynamic sleep
|
if (TasmotaGlobal.sleep && Settings.flag3.sleep_normal) { // SetOption60 - Enable normal sleep instead of dynamic sleep
|
||||||
WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
|
WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
|
||||||
} else {
|
} else {
|
||||||
WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Disable sleep (Esp8288/Arduino core and sdk default)
|
WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Disable sleep (Esp8288/Arduino core and sdk default)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
if (0 == TasmotaGlobal.sleep) {
|
||||||
|
if (!TasmotaGlobal.wifi_stay_asleep) {
|
||||||
|
WiFi.setSleepMode(WIFI_NONE_SLEEP); // Disable sleep
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Settings.flag3.sleep_normal) { // SetOption60 - Enable normal sleep instead of dynamic sleep
|
||||||
|
WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
|
||||||
|
} else {
|
||||||
|
WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Sleep (Esp8288/Arduino core and sdk default)
|
||||||
|
}
|
||||||
|
}
|
||||||
WifiSetOutputPower();
|
WifiSetOutputPower();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,6 +748,7 @@ uint32_t WifiGetNtp(void) {
|
|||||||
char* ntp_server;
|
char* ntp_server;
|
||||||
bool resolved_ip = false;
|
bool resolved_ip = false;
|
||||||
for (uint32_t i = 0; i <= MAX_NTP_SERVERS; i++) {
|
for (uint32_t i = 0; i <= MAX_NTP_SERVERS; i++) {
|
||||||
|
if (ntp_server_id > 2) { ntp_server_id = 0; }
|
||||||
if (i < MAX_NTP_SERVERS) {
|
if (i < MAX_NTP_SERVERS) {
|
||||||
ntp_server = SettingsText(SET_NTPSERVER1 + ntp_server_id);
|
ntp_server = SettingsText(SET_NTPSERVER1 + ntp_server_id);
|
||||||
} else {
|
} else {
|
||||||
@ -747,7 +761,6 @@ uint32_t WifiGetNtp(void) {
|
|||||||
if (resolved_ip) { break; }
|
if (resolved_ip) { break; }
|
||||||
}
|
}
|
||||||
ntp_server_id++;
|
ntp_server_id++;
|
||||||
if (ntp_server_id > 2) { ntp_server_id = 0; }
|
|
||||||
}
|
}
|
||||||
if (!resolved_ip) {
|
if (!resolved_ip) {
|
||||||
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: No server found"));
|
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: No server found"));
|
||||||
@ -785,8 +798,7 @@ uint32_t WifiGetNtp(void) {
|
|||||||
packet_buffer[15] = 52;
|
packet_buffer[15] = 52;
|
||||||
|
|
||||||
if (udp.beginPacket(time_server_ip, 123) == 0) { // NTP requests are to port 123
|
if (udp.beginPacket(time_server_ip, 123) == 0) { // NTP requests are to port 123
|
||||||
ntp_server_id++;
|
ntp_server_id++; // Next server next time
|
||||||
if (ntp_server_id > 2) { ntp_server_id = 0; } // Next server next time
|
|
||||||
udp.stop();
|
udp.stop();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -806,6 +818,7 @@ uint32_t WifiGetNtp(void) {
|
|||||||
// Leap-Indicator: unknown (clock unsynchronized)
|
// Leap-Indicator: unknown (clock unsynchronized)
|
||||||
// See: https://github.com/letscontrolit/ESPEasy/issues/2886#issuecomment-586656384
|
// See: https://github.com/letscontrolit/ESPEasy/issues/2886#issuecomment-586656384
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: IP %s unsynched"), time_server_ip.toString().c_str());
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: IP %s unsynched"), time_server_ip.toString().c_str());
|
||||||
|
ntp_server_id++; // Next server next time
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -816,6 +829,7 @@ uint32_t WifiGetNtp(void) {
|
|||||||
secs_since_1900 |= (uint32_t)packet_buffer[42] << 8;
|
secs_since_1900 |= (uint32_t)packet_buffer[42] << 8;
|
||||||
secs_since_1900 |= (uint32_t)packet_buffer[43];
|
secs_since_1900 |= (uint32_t)packet_buffer[43];
|
||||||
if (0 == secs_since_1900) { // No time stamp received
|
if (0 == secs_since_1900) { // No time stamp received
|
||||||
|
ntp_server_id++; // Next server next time
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return secs_since_1900 - 2208988800UL;
|
return secs_since_1900 - 2208988800UL;
|
||||||
@ -825,6 +839,7 @@ uint32_t WifiGetNtp(void) {
|
|||||||
// Timeout.
|
// Timeout.
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: No reply"));
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: No reply"));
|
||||||
udp.stop();
|
udp.stop();
|
||||||
|
ntp_server_id++; // Next server next time
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,7 @@ struct {
|
|||||||
bool skip_light_fade; // Temporarily skip light fading
|
bool skip_light_fade; // Temporarily skip light fading
|
||||||
bool restart_halt; // Do not restart but stay in wait loop
|
bool restart_halt; // Do not restart but stay in wait loop
|
||||||
bool module_changed; // Indicate module changed since last restart
|
bool module_changed; // Indicate module changed since last restart
|
||||||
|
bool wifi_stay_asleep; // Allow sleep only incase of ESP32 BLE
|
||||||
|
|
||||||
StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits)
|
StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits)
|
||||||
uint8_t spi_enabled; // SPI configured
|
uint8_t spi_enabled; // SPI configured
|
||||||
|
@ -225,8 +225,9 @@ const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in lo
|
|||||||
#error "Arduino ESP8266 Core versions before 2.7.1 are not supported"
|
#error "Arduino ESP8266 Core versions before 2.7.1 are not supported"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TASM_FILE_SETTINGS "/.settings"
|
#define TASM_FILE_SETTINGS "/.settings" // Settings binary blob
|
||||||
#define TASM_FILE_ZIGBEE "/zb"
|
#define TASM_FILE_SETTINGS_LKG "/.settings.lkg" // Last Known Good Settings binary blob
|
||||||
|
#define TASM_FILE_ZIGBEE "/zb" // Zigbee settings blob as used by CC2530 on ESP32
|
||||||
|
|
||||||
#ifndef MQTT_MAX_PACKET_SIZE
|
#ifndef MQTT_MAX_PACKET_SIZE
|
||||||
#define MQTT_MAX_PACKET_SIZE 1200 // Bytes
|
#define MQTT_MAX_PACKET_SIZE 1200 // Bytes
|
||||||
|
@ -475,14 +475,14 @@ void StartWebserver(int type, IPAddress ipweb)
|
|||||||
String ipv6_addr = WifiGetIPv6();
|
String ipv6_addr = WifiGetIPv6();
|
||||||
if (ipv6_addr!="") {
|
if (ipv6_addr!="") {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "),
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "),
|
||||||
NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str(), ipv6_addr.c_str());
|
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str(), ipv6_addr.c_str());
|
||||||
} else {
|
} else {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
|
||||||
NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str());
|
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
|
||||||
NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str());
|
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", ipweb.toString().c_str());
|
||||||
#endif // LWIP_IPV6 = 1
|
#endif // LWIP_IPV6 = 1
|
||||||
TasmotaGlobal.rules_flag.http_init = 1;
|
TasmotaGlobal.rules_flag.http_init = 1;
|
||||||
}
|
}
|
||||||
@ -744,7 +744,7 @@ void WSContentSendStyle_P(const char* formatP, ...)
|
|||||||
bool sip = (static_cast<uint32_t>(WiFi.softAPIP()) != 0);
|
bool sip = (static_cast<uint32_t>(WiFi.softAPIP()) != 0);
|
||||||
WSContentSend_P(PSTR("<h4>%s%s (%s%s%s)</h4>"), // tasmota.local (192.168.2.12, 192.168.4.1)
|
WSContentSend_P(PSTR("<h4>%s%s (%s%s%s)</h4>"), // tasmota.local (192.168.2.12, 192.168.4.1)
|
||||||
NetworkHostname(),
|
NetworkHostname(),
|
||||||
(Mdns.begun) ? ".local" : "",
|
(Mdns.begun) ? PSTR(".local") : "",
|
||||||
(lip) ? WiFi.localIP().toString().c_str() : "",
|
(lip) ? WiFi.localIP().toString().c_str() : "",
|
||||||
(lip && sip) ? ", " : "",
|
(lip && sip) ? ", " : "",
|
||||||
(sip) ? WiFi.softAPIP().toString().c_str() : "");
|
(sip) ? WiFi.softAPIP().toString().c_str() : "");
|
||||||
@ -1230,15 +1230,15 @@ bool HandleRootStatusRefresh(void)
|
|||||||
uint32_t fsize = (TasmotaGlobal.devices_present < 5) ? 70 - (TasmotaGlobal.devices_present * 8) : 32;
|
uint32_t fsize = (TasmotaGlobal.devices_present < 5) ? 70 - (TasmotaGlobal.devices_present * 8) : 32;
|
||||||
#ifdef USE_SONOFF_IFAN
|
#ifdef USE_SONOFF_IFAN
|
||||||
if (IsModuleIfan()) {
|
if (IsModuleIfan()) {
|
||||||
WSContentSend_P(HTTP_DEVICE_STATE, 36, (bitRead(TasmotaGlobal.power, 0)) ? "bold" : "normal", 54, GetStateText(bitRead(TasmotaGlobal.power, 0)));
|
WSContentSend_P(HTTP_DEVICE_STATE, 36, (bitRead(TasmotaGlobal.power, 0)) ? PSTR("bold") : PSTR("normal"), 54, GetStateText(bitRead(TasmotaGlobal.power, 0)));
|
||||||
uint32_t fanspeed = GetFanspeed();
|
uint32_t fanspeed = GetFanspeed();
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fanspeed);
|
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fanspeed);
|
||||||
WSContentSend_P(HTTP_DEVICE_STATE, 64, (fanspeed) ? "bold" : "normal", 54, (fanspeed) ? svalue : GetStateText(0));
|
WSContentSend_P(HTTP_DEVICE_STATE, 64, (fanspeed) ? PSTR("bold") : PSTR("normal"), 54, (fanspeed) ? svalue : GetStateText(0));
|
||||||
} else {
|
} else {
|
||||||
#endif // USE_SONOFF_IFAN
|
#endif // USE_SONOFF_IFAN
|
||||||
for (uint32_t idx = 1; idx <= TasmotaGlobal.devices_present; idx++) {
|
for (uint32_t idx = 1; idx <= TasmotaGlobal.devices_present; idx++) {
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), bitRead(TasmotaGlobal.power, idx -1));
|
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), bitRead(TasmotaGlobal.power, idx -1));
|
||||||
WSContentSend_P(HTTP_DEVICE_STATE, 100 / TasmotaGlobal.devices_present, (bitRead(TasmotaGlobal.power, idx -1)) ? "bold" : "normal", fsize, (TasmotaGlobal.devices_present < 5) ? GetStateText(bitRead(TasmotaGlobal.power, idx -1)) : svalue);
|
WSContentSend_P(HTTP_DEVICE_STATE, 100 / TasmotaGlobal.devices_present, (bitRead(TasmotaGlobal.power, idx -1)) ? PSTR("bold") : PSTR("normal"), fsize, (TasmotaGlobal.devices_present < 5) ? GetStateText(bitRead(TasmotaGlobal.power, idx -1)) : svalue);
|
||||||
}
|
}
|
||||||
#ifdef USE_SONOFF_IFAN
|
#ifdef USE_SONOFF_IFAN
|
||||||
}
|
}
|
||||||
@ -1438,7 +1438,7 @@ void HandleTemplateConfiguration(void)
|
|||||||
for (uint32_t i = 0; i < MAX_GPIO_PIN; i++) {
|
for (uint32_t i = 0; i < MAX_GPIO_PIN; i++) {
|
||||||
if (!FlashPin(i)) {
|
if (!FlashPin(i)) {
|
||||||
WSContentSend_P(PSTR("<tr><td><b><font color='#%06x'>" D_GPIO "%d</font></b></td><td%s><select id='g%d' onchange='ot(%d,this.value)'></select></td>"),
|
WSContentSend_P(PSTR("<tr><td><b><font color='#%06x'>" D_GPIO "%d</font></b></td><td%s><select id='g%d' onchange='ot(%d,this.value)'></select></td>"),
|
||||||
((9==i)||(10==i)) ? WebColor(COL_TEXT_WARNING) : WebColor(COL_TEXT), i, (0==i) ? " style='width:150px'" : "", i, i);
|
((9==i)||(10==i)) ? WebColor(COL_TEXT_WARNING) : WebColor(COL_TEXT), i, (0==i) ? PSTR(" style='width:150px'") : "", i, i);
|
||||||
WSContentSend_P(PSTR("<td style='width:50px'><select id='h%d'></select></td></tr>"), i);
|
WSContentSend_P(PSTR("<td style='width:50px'><select id='h%d'></select></td></tr>"), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1824,7 +1824,7 @@ void HandleLoggingConfiguration(void)
|
|||||||
idx);
|
idx);
|
||||||
for (uint32_t i = LOG_LEVEL_NONE; i <= LOG_LEVEL_DEBUG_MORE; i++) {
|
for (uint32_t i = LOG_LEVEL_NONE; i <= LOG_LEVEL_DEBUG_MORE; i++) {
|
||||||
WSContentSend_P(PSTR("<option%s value='%d'>%d %s</option>"),
|
WSContentSend_P(PSTR("<option%s value='%d'>%d %s</option>"),
|
||||||
(i == llevel) ? " selected" : "", i, i,
|
(i == llevel) ? PSTR(" selected") : "", i, i,
|
||||||
GetTextIndexed(stemp1, sizeof(stemp1), i, kLoggingLevels));
|
GetTextIndexed(stemp1, sizeof(stemp1), i, kLoggingLevels));
|
||||||
}
|
}
|
||||||
WSContentSend_P(PSTR("</select></p>"));
|
WSContentSend_P(PSTR("</select></p>"));
|
||||||
@ -1880,8 +1880,8 @@ void HandleOtherConfiguration(void)
|
|||||||
TemplateJson();
|
TemplateJson();
|
||||||
char stemp[strlen(TasmotaGlobal.mqtt_data) +1];
|
char stemp[strlen(TasmotaGlobal.mqtt_data) +1];
|
||||||
strlcpy(stemp, TasmotaGlobal.mqtt_data, sizeof(stemp)); // Get JSON template
|
strlcpy(stemp, TasmotaGlobal.mqtt_data, sizeof(stemp)); // Get JSON template
|
||||||
WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "",
|
WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? PSTR(" checked disabled") : "",
|
||||||
(Settings.flag.mqtt_enabled) ? " checked" : "", // SetOption3 - Enable MQTT
|
(Settings.flag.mqtt_enabled) ? PSTR(" checked") : "", // SetOption3 - Enable MQTT
|
||||||
SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME));
|
SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME));
|
||||||
|
|
||||||
uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present;
|
uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present;
|
||||||
@ -1911,9 +1911,9 @@ void HandleOtherConfiguration(void)
|
|||||||
if (i < EMUL_MAX) {
|
if (i < EMUL_MAX) {
|
||||||
WSContentSend_P(PSTR("<input id='r%d' name='b2' type='radio' value='%d'%s><b>%s</b> %s<br>"), // Different id only used for labels
|
WSContentSend_P(PSTR("<input id='r%d' name='b2' type='radio' value='%d'%s><b>%s</b> %s<br>"), // Different id only used for labels
|
||||||
i, i,
|
i, i,
|
||||||
(i == Settings.flag2.emulation) ? " checked" : "",
|
(i == Settings.flag2.emulation) ? PSTR(" checked") : "",
|
||||||
GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions),
|
GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions),
|
||||||
(i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE);
|
(i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? PSTR(D_SINGLE_DEVICE) : PSTR(D_MULTI_DEVICE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WSContentSend_P(PSTR("</p></fieldset>"));
|
WSContentSend_P(PSTR("</p></fieldset>"));
|
||||||
@ -2086,7 +2086,7 @@ void HandleInformation(void)
|
|||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#ifdef USE_ETHERNET
|
#ifdef USE_ETHERNET
|
||||||
if (static_cast<uint32_t>(EthernetLocalIP()) != 0) {
|
if (static_cast<uint32_t>(EthernetLocalIP()) != 0) {
|
||||||
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? ".local" : "");
|
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? PSTR(".local") : "");
|
||||||
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
|
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
|
||||||
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%s"), EthernetLocalIP().toString().c_str());
|
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%s"), EthernetLocalIP().toString().c_str());
|
||||||
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
|
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
|
||||||
@ -2096,7 +2096,7 @@ void HandleInformation(void)
|
|||||||
if (Settings.flag4.network_wifi) {
|
if (Settings.flag4.network_wifi) {
|
||||||
int32_t rssi = WiFi.RSSI();
|
int32_t rssi = WiFi.RSSI();
|
||||||
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings.sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi);
|
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings.sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi);
|
||||||
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? ".local" : "");
|
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? PSTR(".local") : "");
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
String ipv6_addr = WifiGetIPv6();
|
String ipv6_addr = WifiGetIPv6();
|
||||||
if (ipv6_addr != "") {
|
if (ipv6_addr != "") {
|
||||||
@ -2169,15 +2169,15 @@ void HandleInformation(void)
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId());
|
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId());
|
||||||
#endif
|
#endif
|
||||||
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024);
|
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%d kB"), ESP.getFlashChipRealSize() / 1024);
|
||||||
WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024);
|
WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%d kB"), ESP.getFlashChipSize() / 1024);
|
||||||
WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP_getSketchSize() / 1024);
|
WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%d kB"), ESP_getSketchSize() / 1024);
|
||||||
WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024);
|
WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%d kB"), ESP.getFreeSketchSpace() / 1024);
|
||||||
WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%dkB"), freeMem / 1024);
|
WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%d kB"), freeMem / 1024);
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
if (psramFound()) {
|
if (psramFound()) {
|
||||||
WSContentSend_P(PSTR("}1" D_PSR_MAX_MEMORY "}2%dkB"), ESP.getPsramSize() / 1024);
|
WSContentSend_P(PSTR("}1" D_PSR_MAX_MEMORY "}2%d kB"), ESP.getPsramSize() / 1024);
|
||||||
WSContentSend_P(PSTR("}1" D_PSR_FREE_MEMORY "}2%dkB"), ESP.getFreePsram() / 1024);
|
WSContentSend_P(PSTR("}1" D_PSR_FREE_MEMORY "}2%d kB"), ESP.getFreePsram() / 1024);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
WSContentSend_P(PSTR("</td></tr></table>"));
|
WSContentSend_P(PSTR("</td></tr></table>"));
|
||||||
@ -2522,7 +2522,7 @@ void HandleUploadLoop(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (upload.totalSize && !(upload.totalSize % 102400)) {
|
if (upload.totalSize && !(upload.totalSize % 102400)) {
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Progress %dkB"), upload.totalSize / 1024);
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Progress %d kB"), upload.totalSize / 1024);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2788,7 +2788,7 @@ bool CaptivePortal(void)
|
|||||||
if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) {
|
if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) {
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED));
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED));
|
||||||
|
|
||||||
Webserver->sendHeader(F("Location"), String("http://") + Webserver->client().localIP().toString(), true);
|
Webserver->sendHeader(F("Location"), String(F("http://")) + Webserver->client().localIP().toString(), true);
|
||||||
WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||||
Webserver->client().stop(); // Stop is needed because we sent no content length
|
Webserver->client().stop(); // Stop is needed because we sent no content length
|
||||||
return true;
|
return true;
|
||||||
|
@ -679,8 +679,13 @@ void MqttReconnect(void) {
|
|||||||
if (MqttClient.connect(TasmotaGlobal.mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, lwt_retain, TasmotaGlobal.mqtt_data, MQTT_CLEAN_SESSION)) {
|
if (MqttClient.connect(TasmotaGlobal.mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, lwt_retain, TasmotaGlobal.mqtt_data, MQTT_CLEAN_SESSION)) {
|
||||||
#ifdef USE_MQTT_TLS
|
#ifdef USE_MQTT_TLS
|
||||||
if (Mqtt.mqtt_tls) {
|
if (Mqtt.mqtt_tls) {
|
||||||
|
#ifdef ESP8266
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms, max ThunkStack used %d"),
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms, max ThunkStack used %d"),
|
||||||
millis() - mqtt_connect_time, tlsClient->getMaxThunkStackUse());
|
millis() - mqtt_connect_time, tlsClient->getMaxThunkStackUse());
|
||||||
|
#elif defined(ESP32)
|
||||||
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms, stack low mark %d"),
|
||||||
|
millis() - mqtt_connect_time, uxTaskGetStackHighWaterMark(nullptr));
|
||||||
|
#endif
|
||||||
if (!tlsClient->getMFLNStatus()) {
|
if (!tlsClient->getMFLNStatus()) {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "MFLN not supported by TLS server"));
|
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "MFLN not supported by TLS server"));
|
||||||
}
|
}
|
||||||
@ -1275,7 +1280,7 @@ void HandleMqttConfiguration(void)
|
|||||||
SettingsText(SET_MQTT_HOST),
|
SettingsText(SET_MQTT_HOST),
|
||||||
Settings.mqtt_port,
|
Settings.mqtt_port,
|
||||||
#ifdef USE_MQTT_TLS
|
#ifdef USE_MQTT_TLS
|
||||||
Mqtt.mqtt_tls ? " checked" : "", // SetOption102 - Enable MQTT TLS
|
Mqtt.mqtt_tls ? PSTR(" checked") : "", // SetOption102 - Enable MQTT TLS
|
||||||
#endif // USE_MQTT_TLS
|
#endif // USE_MQTT_TLS
|
||||||
Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, SettingsText(SET_MQTT_CLIENT));
|
Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, SettingsText(SET_MQTT_CLIENT));
|
||||||
WSContentSend_P(HTTP_FORM_MQTT2,
|
WSContentSend_P(HTTP_FORM_MQTT2,
|
||||||
|
@ -537,6 +537,7 @@ void EnergyEverySecond(void)
|
|||||||
}
|
}
|
||||||
if (!data_valid) {
|
if (!data_valid) {
|
||||||
Energy.start_energy = 0;
|
Energy.start_energy = 0;
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NRG: Energy reset by " STR(ENERGY_WATCHDOG) " seconds invalid data"));
|
||||||
|
|
||||||
XnrgCall(FUNC_ENERGY_RESET);
|
XnrgCall(FUNC_ENERGY_RESET);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,7 @@ void PrepShowTimer(uint32_t index)
|
|||||||
char days[8] = { 0 };
|
char days[8] = { 0 };
|
||||||
for (uint32_t i = 0; i < 7; i++) {
|
for (uint32_t i = 0; i < 7; i++) {
|
||||||
uint8_t mask = 1 << i;
|
uint8_t mask = 1 << i;
|
||||||
snprintf(days, sizeof(days), "%s%d", days, ((xtimer.days & mask) > 0));
|
snprintf(days, sizeof(days), PSTR("%s%d"), days, ((xtimer.days & mask) > 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
char soutput[80];
|
char soutput[80];
|
||||||
@ -857,7 +857,7 @@ void HandleTimerConfiguration(void)
|
|||||||
WSContentSend_P(HTTP_TIMER_SCRIPT5, MAX_TIMERS, TasmotaGlobal.devices_present);
|
WSContentSend_P(HTTP_TIMER_SCRIPT5, MAX_TIMERS, TasmotaGlobal.devices_present);
|
||||||
WSContentSend_P(HTTP_TIMER_SCRIPT6, TasmotaGlobal.devices_present);
|
WSContentSend_P(HTTP_TIMER_SCRIPT6, TasmotaGlobal.devices_present);
|
||||||
WSContentSendStyle_P(HTTP_TIMER_STYLE, WebColor(COL_FORM));
|
WSContentSendStyle_P(HTTP_TIMER_STYLE, WebColor(COL_FORM));
|
||||||
WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? " checked" : ""); // CMND_TIMERS
|
WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? PSTR(" checked") : ""); // CMND_TIMERS
|
||||||
for (uint32_t i = 0; i < MAX_TIMERS; i++) {
|
for (uint32_t i = 0; i < MAX_TIMERS; i++) {
|
||||||
WSContentSend_P(PSTR("%s%u"), (i > 0) ? "," : "", Settings.timer[i].data);
|
WSContentSend_P(PSTR("%s%u"), (i > 0) ? "," : "", Settings.timer[i].data);
|
||||||
}
|
}
|
||||||
|
@ -4550,53 +4550,59 @@ int16_t Run_script_sub(const char *type, int8_t tlen, JsonParserObject *jo) {
|
|||||||
if (*ctype=='#') {
|
if (*ctype=='#') {
|
||||||
// check for parameter
|
// check for parameter
|
||||||
ctype += tlen;
|
ctype += tlen;
|
||||||
if (*ctype=='(' && *(lp+tlen)=='(') {
|
char nxttok = '(';
|
||||||
float fparam;
|
char *argptr = ctype+tlen;
|
||||||
numeric = 1;
|
|
||||||
glob_script_mem.glob_error = 0;
|
lp += tlen;
|
||||||
GetNumericArgument((char*)ctype, OPER_EQU, &fparam, 0);
|
do {
|
||||||
if (glob_script_mem.glob_error==1) {
|
if (*ctype==nxttok && *lp==nxttok) {
|
||||||
// was string, not number
|
float fparam;
|
||||||
numeric = 0;
|
numeric = 1;
|
||||||
// get the string
|
glob_script_mem.glob_error = 0;
|
||||||
GetStringArgument((char*)ctype + 1, OPER_EQU, cmpstr, 0);
|
argptr = GetNumericArgument((char*)ctype + 1, OPER_EQU, &fparam, 0);
|
||||||
}
|
if (glob_script_mem.glob_error==1) {
|
||||||
lp += tlen;
|
// was string, not number
|
||||||
if (*lp=='(') {
|
numeric = 0;
|
||||||
// fetch destination
|
// get the string
|
||||||
lp++;
|
argptr = GetStringArgument((char*)ctype + 1, OPER_EQU, cmpstr, 0);
|
||||||
lp = isvar(lp, &vtype, &ind, 0, 0, 0);
|
}
|
||||||
if (vtype!=VAR_NV) {
|
if (*lp==nxttok) {
|
||||||
// found variable as result
|
// fetch destination
|
||||||
uint8_t index = glob_script_mem.type[ind.index].index;
|
lp++;
|
||||||
if ((vtype&STYPE)==0) {
|
lp = isvar(lp, &vtype, &ind, 0, 0, 0);
|
||||||
// numeric result
|
if (vtype!=VAR_NV) {
|
||||||
dfvar = &glob_script_mem.fvars[index];
|
// found variable as result
|
||||||
if (numeric) {
|
uint8_t index = glob_script_mem.type[ind.index].index;
|
||||||
*dfvar = fparam;
|
if ((vtype&STYPE)==0) {
|
||||||
} else {
|
// numeric result
|
||||||
// mismatch
|
dfvar = &glob_script_mem.fvars[index];
|
||||||
*dfvar = CharToFloat(cmpstr);
|
if (numeric) {
|
||||||
}
|
*dfvar = fparam;
|
||||||
} else {
|
} else {
|
||||||
// string result
|
// mismatch
|
||||||
sindex = index;
|
*dfvar = CharToFloat(cmpstr);
|
||||||
if (!numeric) {
|
}
|
||||||
strlcpy(glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize), cmpstr, glob_script_mem.max_ssize);
|
} else {
|
||||||
} else {
|
// string result
|
||||||
// mismatch
|
sindex = index;
|
||||||
dtostrfd(fparam, 6, glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize));
|
if (!numeric) {
|
||||||
}
|
strlcpy(glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize), cmpstr, glob_script_mem.max_ssize);
|
||||||
|
} else {
|
||||||
|
// mismatch
|
||||||
|
dtostrfd(fparam, 6, glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (*ctype==nxttok || (*lp!=SCRIPT_EOL && *lp!='?')) {
|
||||||
|
// revert
|
||||||
|
section = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
nxttok = ' ';
|
||||||
lp += tlen;
|
ctype = argptr;
|
||||||
if (*ctype=='(' || (*lp!=SCRIPT_EOL && *lp!='?')) {
|
} while (*lp==' ' && (section == 1) );
|
||||||
// revert
|
|
||||||
section = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4973,9 +4979,9 @@ void HandleScriptConfiguration(void) {
|
|||||||
#ifdef xSCRIPT_STRIP_COMMENTS
|
#ifdef xSCRIPT_STRIP_COMMENTS
|
||||||
uint16_t ssize = glob_script_mem.script_size;
|
uint16_t ssize = glob_script_mem.script_size;
|
||||||
if (bitRead(Settings.rule_enabled, 1)) ssize *= 2;
|
if (bitRead(Settings.rule_enabled, 1)) ssize *= 2;
|
||||||
WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",ssize);
|
WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? PSTR(" checked") : "",ssize);
|
||||||
#else
|
#else
|
||||||
WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",glob_script_mem.script_size);
|
WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? PSTR(" checked") : "",glob_script_mem.script_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// script is to large for WSContentSend_P
|
// script is to large for WSContentSend_P
|
||||||
|
@ -197,7 +197,7 @@ const char HASS_DISCOVER_DEVICE[] PROGMEM = // Basic par
|
|||||||
"\"tp\":[\"%s\",\"%s\",\"%s\"]," // Topics for command, stat and tele
|
"\"tp\":[\"%s\",\"%s\",\"%s\"]," // Topics for command, stat and tele
|
||||||
"\"rl\":[%s],\"swc\":[%s],\"swn\":[%s],\"btn\":[%s]," // Inputs / Outputs
|
"\"rl\":[%s],\"swc\":[%s],\"swn\":[%s],\"btn\":[%s]," // Inputs / Outputs
|
||||||
"\"so\":{\"4\":%d,\"11\":%d,\"13\":%d,\"17\":%d,\"20\":%d," // SetOptions
|
"\"so\":{\"4\":%d,\"11\":%d,\"13\":%d,\"17\":%d,\"20\":%d," // SetOptions
|
||||||
"\"30\":%d,\"68\":%d,\"73\":%d,\"82\":%d,\"114\":%d},"
|
"\"30\":%d,\"68\":%d,\"73\":%d,\"82\":%d,\"114\":%d,\"117\":%d},"
|
||||||
"\"lk\":%d,\"lt_st\":%d,\"sho\":[%s],\"ver\":1}"; // Light SubType, Shutter Options and Discovery version
|
"\"lk\":%d,\"lt_st\":%d,\"sho\":[%s],\"ver\":1}"; // Light SubType, Shutter Options and Discovery version
|
||||||
|
|
||||||
typedef struct HASS {
|
typedef struct HASS {
|
||||||
@ -341,7 +341,7 @@ void NewHAssDiscovery(void)
|
|||||||
TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), SUB_PREFIX, PUB_PREFIX, PUB_PREFIX2, Hass.RelLst, stemp3, stemp4,
|
TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), SUB_PREFIX, PUB_PREFIX, PUB_PREFIX2, Hass.RelLst, stemp3, stemp4,
|
||||||
stemp5, Settings.flag.mqtt_response, Settings.flag.button_swap, Settings.flag.button_single, Settings.flag.decimal_text, Settings.flag.not_power_linked,
|
stemp5, Settings.flag.mqtt_response, Settings.flag.button_swap, Settings.flag.button_single, Settings.flag.decimal_text, Settings.flag.not_power_linked,
|
||||||
Settings.flag.hass_light, Settings.flag3.pwm_multi_channels, Settings.flag3.mqtt_buttons, Settings.flag4.alexa_ct_range, Settings.flag5.mqtt_switches,
|
Settings.flag.hass_light, Settings.flag3.pwm_multi_channels, Settings.flag3.mqtt_buttons, Settings.flag4.alexa_ct_range, Settings.flag5.mqtt_switches,
|
||||||
light_controller.isCTRGBLinked(), Light.subtype, stemp6);
|
Settings.flag5.fade_fixed_duration, light_controller.isCTRGBLinked(), Light.subtype, stemp6);
|
||||||
}
|
}
|
||||||
MqttPublish(stopic, true);
|
MqttPublish(stopic, true);
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ String HueBridgeId(void)
|
|||||||
String temp = WiFi.macAddress();
|
String temp = WiFi.macAddress();
|
||||||
temp.replace(":", "");
|
temp.replace(":", "");
|
||||||
String bridgeid = temp.substring(0, 6);
|
String bridgeid = temp.substring(0, 6);
|
||||||
bridgeid += "FFFE";
|
bridgeid += F("FFFE");
|
||||||
bridgeid += temp.substring(6);
|
bridgeid += temp.substring(6);
|
||||||
return bridgeid; // 5CCF7FFFFE139F3D
|
return bridgeid; // 5CCF7FFFFE139F3D
|
||||||
}
|
}
|
||||||
@ -225,8 +225,6 @@ void HueRespondToMSearch(void)
|
|||||||
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"),
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"),
|
||||||
message, udp_remote_ip.toString().c_str(), udp_remote_port);
|
message, udp_remote_ip.toString().c_str(), udp_remote_port);
|
||||||
|
|
||||||
udp_response_mutex = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
@ -76,8 +76,6 @@ void WemoRespondToMSearch(int echo_type)
|
|||||||
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
|
||||||
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
|
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
|
||||||
|
|
||||||
udp_response_mutex = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
@ -422,8 +422,6 @@ void WemoRespondToMSearch(int echo_type) {
|
|||||||
for (uint32_t i = 0; i < numOfWemoSwitch; i++) {
|
for (uint32_t i = 0; i < numOfWemoSwitch; i++) {
|
||||||
wemoDevice[i]->WemoRespondToMSearch(echo_type);
|
wemoDevice[i]->WemoRespondToMSearch(echo_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
udp_response_mutex = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
@ -681,9 +681,9 @@ void Z_Device::jsonAddConfig(Z_attribute_list & attr_list) const {
|
|||||||
for (auto & data_elt : data) {
|
for (auto & data_elt : data) {
|
||||||
char key[8];
|
char key[8];
|
||||||
if (data_elt.validConfig()) {
|
if (data_elt.validConfig()) {
|
||||||
snprintf_P(key, sizeof(key), "?%02X.%1X", data_elt.getEndpoint(), data_elt.getConfig());
|
snprintf_P(key, sizeof(key), PSTR("?%02X.%1X"), data_elt.getEndpoint(), data_elt.getConfig());
|
||||||
} else {
|
} else {
|
||||||
snprintf_P(key, sizeof(key), "?%02X", data_elt.getEndpoint());
|
snprintf_P(key, sizeof(key), PSTR("?%02X"), data_elt.getEndpoint());
|
||||||
}
|
}
|
||||||
key[0] = Z_Data::DataTypeToChar(data_elt.getType());
|
key[0] = Z_Data::DataTypeToChar(data_elt.getType());
|
||||||
arr_data.addStr(key);
|
arr_data.addStr(key);
|
||||||
|
@ -1903,7 +1903,7 @@ void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class
|
|||||||
y = buf2.get16(2);
|
y = buf2.get16(2);
|
||||||
x = buf2.get16(4);
|
x = buf2.get16(4);
|
||||||
char temp[32];
|
char temp[32];
|
||||||
snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", x, y, z);
|
snprintf_P(temp, sizeof(temp), PSTR("[%i,%i,%i]"), x, y, z);
|
||||||
attr.setStrRaw(temp);
|
attr.setStrRaw(temp);
|
||||||
// calculate angles
|
// calculate angles
|
||||||
float X = x;
|
float X = x;
|
||||||
@ -1912,7 +1912,7 @@ void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class
|
|||||||
int32_t Angle_X = 0.5f + atanf(X/sqrtf(z*z+y*y)) * f_180pi;
|
int32_t Angle_X = 0.5f + atanf(X/sqrtf(z*z+y*y)) * f_180pi;
|
||||||
int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi;
|
int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi;
|
||||||
int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi;
|
int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi;
|
||||||
snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", Angle_X, Angle_Y, Angle_Z);
|
snprintf_P(temp, sizeof(temp), PSTR("[%i,%i,%i]"), Angle_X, Angle_Y, Angle_Z);
|
||||||
attr_list.addAttributePMEM(PSTR("AqaraAngles")).setStrRaw(temp);
|
attr_list.addAttributePMEM(PSTR("AqaraAngles")).setStrRaw(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -785,7 +785,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
|||||||
ZI_WAIT_UNTIL(5000, ZBR_RSTACK) // wait for RSTACK message
|
ZI_WAIT_UNTIL(5000, ZBR_RSTACK) // wait for RSTACK message
|
||||||
|
|
||||||
// Init device and probe version
|
// Init device and probe version
|
||||||
ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(1000, ZBR_VERSION, &EZ_ReceiveCheckVersion) // check EXT PAN ID
|
ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(5000, ZBR_VERSION, &EZ_ReceiveCheckVersion) // check EXT PAN ID
|
||||||
|
|
||||||
// configure EFR32
|
// configure EFR32
|
||||||
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
|
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
|
||||||
|
@ -171,7 +171,7 @@ void Z_Mapper::dumpInternals(void) const {
|
|||||||
char hex[8];
|
char hex[8];
|
||||||
snprintf(hex, sizeof(hex), PSTR("%d"), edge.lqi);
|
snprintf(hex, sizeof(hex), PSTR("%d"), edge.lqi);
|
||||||
|
|
||||||
WSContentSend_P("{from:\"0x%04X\",to:\"0x%04X\",label:\"%s\",color:\"#%03X\"},",
|
WSContentSend_P(PSTR("{from:\"0x%04X\",to:\"0x%04X\",label:\"%s\",color:\"#%03X\"},"),
|
||||||
edge.node_1, edge.node_2, (edge.lqi > 0) ? hex : "", lqi_color);
|
edge.node_1, edge.node_2, (edge.lqi > 0) ? hex : "", lqi_color);
|
||||||
}
|
}
|
||||||
WSContentSend_P(PSTR("],"));
|
WSContentSend_P(PSTR("],"));
|
||||||
|
@ -2081,7 +2081,7 @@ void ZigbeeShow(bool json)
|
|||||||
if (zigbee.permit_end_time) {
|
if (zigbee.permit_end_time) {
|
||||||
// PermitJoin in progress
|
// PermitJoin in progress
|
||||||
|
|
||||||
WSContentSend_P(msg[ZB_WEB_PERMITJOIN_ACTIVE], D_ZIGBEE_PERMITJOIN_ACTIVE);
|
WSContentSend_P(msg[ZB_WEB_PERMITJOIN_ACTIVE], PSTR(D_ZIGBEE_PERMITJOIN_ACTIVE));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ void HandlePcf8574(void)
|
|||||||
|
|
||||||
WSContentStart_P(D_CONFIGURE_PCF8574);
|
WSContentStart_P(D_CONFIGURE_PCF8574);
|
||||||
WSContentSendStyle();
|
WSContentSendStyle();
|
||||||
WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings.flag3.pcf8574_ports_inverted) ? " checked" : ""); // SetOption81 - Invert all ports on PCF8574 devices
|
WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings.flag3.pcf8574_ports_inverted) ? PSTR(" checked") : ""); // SetOption81 - Invert all ports on PCF8574 devices
|
||||||
WSContentSend_P(HTTP_TABLE100);
|
WSContentSend_P(HTTP_TABLE100);
|
||||||
for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) {
|
for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) {
|
||||||
for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574
|
for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574
|
||||||
@ -177,8 +177,8 @@ void HandlePcf8574(void)
|
|||||||
idx +1, idx2,
|
idx +1, idx2,
|
||||||
idx2 + 8*idx,
|
idx2 + 8*idx,
|
||||||
idx2 + 8*idx,
|
idx2 + 8*idx,
|
||||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? " selected " : " ",
|
((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? PSTR(" selected ") : " ",
|
||||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? " selected " : " "
|
((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? PSTR(" selected ") : " "
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,12 +418,12 @@ void MLX90640HandleWebGuiResponse(void){
|
|||||||
if(_line==0){_buf[0]=1000+MLX90640.Ta;} //ambient temperature modulation hack
|
if(_line==0){_buf[0]=1000+MLX90640.Ta;} //ambient temperature modulation hack
|
||||||
else{_buf[0]=(float)_line;}
|
else{_buf[0]=(float)_line;}
|
||||||
memcpy((char*)&_buf[1],(char*)&MLX90640.To[_line*64],64*4);
|
memcpy((char*)&_buf[1],(char*)&MLX90640.To[_line*64],64*4);
|
||||||
Webserver->send(200,PSTR("application/octet-stream"),(const char*)&_buf,65*4);
|
Webserver->send_P(200,PSTR("application/octet-stream"),(const char*)&_buf,65*4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebGetArg("up", tmp, sizeof(tmp)); // update POI to browser
|
WebGetArg("up", tmp, sizeof(tmp)); // update POI to browser
|
||||||
if (strlen(tmp)==1) {
|
if (strlen(tmp)==1) {
|
||||||
Webserver->send(200,PSTR("application/octet-stream"),(const char*)&MLX90640.pois,MLX90640_POI_NUM*2);
|
Webserver->send_P(200,PSTR("application/octet-stream"),(const char*)&MLX90640.pois,MLX90640_POI_NUM*2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (strlen(tmp)>2) { // receive updated POI from browser
|
else if (strlen(tmp)>2) { // receive updated POI from browser
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef USE_TIMEPROP
|
#ifdef USE_TIMEPROP
|
||||||
|
#ifndef FIRMWARE_MINIMAL
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Code to drive one or more relays in a time proportioned manner give a
|
* Code to drive one or more relays in a time proportioned manner give a
|
||||||
* required power value.
|
* required power value.
|
||||||
@ -79,7 +80,23 @@
|
|||||||
#define TIMEPROP_RELAYS 1, 2 // which relay to control 1:8
|
#define TIMEPROP_RELAYS 1, 2 // which relay to control 1:8
|
||||||
|
|
||||||
* Publish values between 0 and 1 to the topic(s) described above
|
* Publish values between 0 and 1 to the topic(s) described above
|
||||||
\*********************************************************************************************/
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define D_CMND_TIMEPROP "timeprop_"
|
||||||
|
#define D_CMND_TIMEPROP_SETPOWER "setpower_" // add index no on end (0:8) and data is power 0:1
|
||||||
|
|
||||||
|
#include "Timeprop.h"
|
||||||
|
|
||||||
|
enum TimepropCommands { CMND_TIMEPROP_SETPOWER };
|
||||||
|
const char kTimepropCommands[] PROGMEM = D_CMND_TIMEPROP_SETPOWER;
|
||||||
|
|
||||||
|
static Timeprop timeprops[TIMEPROP_NUM_OUTPUTS];
|
||||||
|
static int relayNos[TIMEPROP_NUM_OUTPUTS] = {TIMEPROP_RELAYS};
|
||||||
|
static long currentRelayStates = 0; // current actual relay states. Bit 0 first relay
|
||||||
|
|
||||||
|
|
||||||
#ifndef TIMEPROP_NUM_OUTPUTS
|
#ifndef TIMEPROP_NUM_OUTPUTS
|
||||||
#define TIMEPROP_NUM_OUTPUTS 1 // how many outputs to control (with separate alogorithm for each)
|
#define TIMEPROP_NUM_OUTPUTS 1 // how many outputs to control (with separate alogorithm for each)
|
||||||
@ -103,8 +120,6 @@
|
|||||||
#define TIMEPROP_RELAYS 1 // which relay to control 1:8
|
#define TIMEPROP_RELAYS 1 // which relay to control 1:8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Timeprop.h"
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Timeprop timeprops[TIMEPROP_NUM_OUTPUTS];
|
Timeprop timeprops[TIMEPROP_NUM_OUTPUTS];
|
||||||
int relay_nos[TIMEPROP_NUM_OUTPUTS] = {TIMEPROP_RELAYS};
|
int relay_nos[TIMEPROP_NUM_OUTPUTS] = {TIMEPROP_RELAYS};
|
||||||
@ -162,7 +177,51 @@ void TimepropXdrvPower(void) {
|
|||||||
/* char *data; */
|
/* char *data; */
|
||||||
/* } XdrvMailbox; */
|
/* } XdrvMailbox; */
|
||||||
|
|
||||||
// To get here post with topic cmnd/timeprop_setpower_n where n is index into Tprop.timeprops 0:7
|
// To get here post with topic cmnd/timeprop_setpower_n where n is index into timeprops 0:7
|
||||||
|
bool TimepropCommand()
|
||||||
|
{
|
||||||
|
char command [CMDSZ];
|
||||||
|
bool serviced = true;
|
||||||
|
uint8_t ua_prefix_len = strlen(D_CMND_TIMEPROP); // to detect prefix of command
|
||||||
|
/*
|
||||||
|
snprintf_P(log_data, sizeof(log_data), "Command called: "
|
||||||
|
"index: %d data_len: %d payload: %d topic: %s data: %s\n",
|
||||||
|
XdrvMailbox.index,
|
||||||
|
XdrvMailbox.data_len,
|
||||||
|
XdrvMailbox.payload,
|
||||||
|
(XdrvMailbox.payload >= 0 ? XdrvMailbox.topic : ""),
|
||||||
|
(XdrvMailbox.data_len >= 0 ? XdrvMailbox.data : ""));
|
||||||
|
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
*/
|
||||||
|
if (0 == strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_TIMEPROP), ua_prefix_len)) {
|
||||||
|
// command starts with timeprop_
|
||||||
|
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + ua_prefix_len, kTimepropCommands);
|
||||||
|
if (CMND_TIMEPROP_SETPOWER == command_code) {
|
||||||
|
/*
|
||||||
|
snprintf_P(log_data, sizeof(log_data), "Timeprop command timeprop_setpower: "
|
||||||
|
"index: %d data_len: %d payload: %d topic: %s data: %s",
|
||||||
|
XdrvMailbox.index,
|
||||||
|
XdrvMailbox.data_len,
|
||||||
|
XdrvMailbox.payload,
|
||||||
|
(XdrvMailbox.payload >= 0 ? XdrvMailbox.topic : ""),
|
||||||
|
(XdrvMailbox.data_len >= 0 ? XdrvMailbox.data : ""));
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
*/
|
||||||
|
if (XdrvMailbox.index >=0 && XdrvMailbox.index < TIMEPROP_NUM_OUTPUTS) {
|
||||||
|
timeprops[XdrvMailbox.index].setPower( atof(XdrvMailbox.data), Tprop.current_time_secs );
|
||||||
|
}
|
||||||
|
snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"" D_CMND_TIMEPROP D_CMND_TIMEPROP_SETPOWER "%d\":\"%s\"}"),
|
||||||
|
XdrvMailbox.index, XdrvMailbox.data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serviced = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
serviced = false;
|
||||||
|
}
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Interface
|
* Interface
|
||||||
@ -180,6 +239,9 @@ bool Xdrv48(byte function) {
|
|||||||
case FUNC_EVERY_SECOND:
|
case FUNC_EVERY_SECOND:
|
||||||
TimepropEverySecond();
|
TimepropEverySecond();
|
||||||
break;
|
break;
|
||||||
|
case FUNC_COMMAND:
|
||||||
|
result = TimepropCommand();
|
||||||
|
break;
|
||||||
case FUNC_SET_POWER:
|
case FUNC_SET_POWER:
|
||||||
TimepropXdrvPower();
|
TimepropXdrvPower();
|
||||||
break;
|
break;
|
||||||
@ -187,4 +249,5 @@ bool Xdrv48(byte function) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // FIRMWARE_MINIMAL
|
||||||
#endif // USE_TIMEPROP
|
#endif // USE_TIMEPROP
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef USE_PID
|
#ifdef USE_PID
|
||||||
|
#ifndef FIRMWARE_MINIMAL
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Uses the library https://github.com/colinl/process-control.git from Github
|
* Uses the library https://github.com/colinl/process-control.git from Github
|
||||||
* In user_config_override.h include code as follows:
|
* In user_config_override.h include code as follows:
|
||||||
@ -117,11 +118,6 @@
|
|||||||
#define PID_REPORT_MORE_SETTINGS // If defined, the SENSOR output will provide more extensive json
|
#define PID_REPORT_MORE_SETTINGS // If defined, the SENSOR output will provide more extensive json
|
||||||
// output in the PID section
|
// output in the PID section
|
||||||
|
|
||||||
// #define PID_BACKWARD_COMPATIBLE // Preserve the backward compatible reporting of PID power via
|
|
||||||
// `%topic%/PID {"power":"0.000"}` This is now available in
|
|
||||||
// `%topic$/SENSOR {..., "PID":{"PidPower":0.00}}`
|
|
||||||
// Don't use unless you know that you need it
|
|
||||||
|
|
||||||
* Help with using the PID algorithm and with loop tuning can be found at
|
* Help with using the PID algorithm and with loop tuning can be found at
|
||||||
* http://blog.clanlaw.org.uk/2018/01/09/PID-tuning-with-node-red-contrib-pid.html
|
* http://blog.clanlaw.org.uk/2018/01/09/PID-tuning-with-node-red-contrib-pid.html
|
||||||
* This is directed towards using the algorithm in the node-red node node-red-contrib-pid but the algorithm here is based on
|
* This is directed towards using the algorithm in the node-red node node-red-contrib-pid but the algorithm here is based on
|
||||||
@ -271,26 +267,27 @@ void CmndSetPv(void) {
|
|||||||
// this runs it at the next second
|
// this runs it at the next second
|
||||||
Pid.run_pid_now = true;
|
Pid.run_pid_now = true;
|
||||||
}
|
}
|
||||||
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetSp(void) {
|
void CmndSetSp(void) {
|
||||||
Pid.pid.setSp(atof(XdrvMailbox.data));
|
Pid.pid.setSp(atof(XdrvMailbox.data));
|
||||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetPb(void) {
|
void CmndSetPb(void) {
|
||||||
Pid.pid.setPb(atof(XdrvMailbox.data));
|
Pid.pid.setPb(atof(XdrvMailbox.data));
|
||||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetTi(void) {
|
void CmndSetTi(void) {
|
||||||
Pid.pid.setTi(atof(XdrvMailbox.data));
|
Pid.pid.setTi(atof(XdrvMailbox.data));
|
||||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetTd(void) {
|
void CmndSetTd(void) {
|
||||||
Pid.pid.setTd(atof(XdrvMailbox.data));
|
Pid.pid.setTd(atof(XdrvMailbox.data));
|
||||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetInitialInt(void) {
|
void CmndSetInitialInt(void) {
|
||||||
@ -300,7 +297,7 @@ void CmndSetInitialInt(void) {
|
|||||||
|
|
||||||
void CmndSetDSmooth(void) {
|
void CmndSetDSmooth(void) {
|
||||||
Pid.pid.setDSmooth(atof(XdrvMailbox.data));
|
Pid.pid.setDSmooth(atof(XdrvMailbox.data));
|
||||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetAuto(void) {
|
void CmndSetAuto(void) {
|
||||||
@ -310,7 +307,7 @@ void CmndSetAuto(void) {
|
|||||||
|
|
||||||
void CmndSetManualPower(void) {
|
void CmndSetManualPower(void) {
|
||||||
Pid.pid.setManualPower(atof(XdrvMailbox.data));
|
Pid.pid.setManualPower(atof(XdrvMailbox.data));
|
||||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmndSetMaxInterval(void) {
|
void CmndSetMaxInterval(void) {
|
||||||
@ -391,14 +388,14 @@ void PIDShowValues(void) {
|
|||||||
|
|
||||||
void PIDRun(void) {
|
void PIDRun(void) {
|
||||||
double power = Pid.pid.tick(Pid.current_time_secs);
|
double power = Pid.pid.tick(Pid.current_time_secs);
|
||||||
#ifdef PID_BACKWARD_COMPATIBLE
|
#ifdef PID_DONT_USE_PID_TOPIC
|
||||||
// This part is left inside to regularly publish the PID Power via
|
// This part is left inside to regularly publish the PID Power via
|
||||||
// `%topic%/PID {"power":"0.000"}`
|
// `%topic%/PID {"power":"0.000"}`
|
||||||
char str_buf[FLOATSZ];
|
char str_buf[FLOATSZ];
|
||||||
dtostrfd(power, 3, str_buf);
|
dtostrfd(power, 3, str_buf);
|
||||||
snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s\":\"%s\"}"), "power", str_buf);
|
snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s\":\"%s\"}"), "power", str_buf);
|
||||||
MqttPublishPrefixTopic_P(TELE, "PID", false);
|
MqttPublishPrefixTopic_P(TELE, "PID", false);
|
||||||
#endif // PID_BACKWARD_COMPATIBLE
|
#endif // PID_DONT_USE_PID_TOPIC
|
||||||
|
|
||||||
#if defined PID_SHUTTER
|
#if defined PID_SHUTTER
|
||||||
// send output as a position from 0-100 to defined shutter
|
// send output as a position from 0-100 to defined shutter
|
||||||
@ -443,4 +440,5 @@ bool Xdrv49(byte function) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
#endif //FIRMWARE_MINIMAL
|
||||||
#endif // USE_PID
|
#endif // USE_PID
|
||||||
|
@ -72,25 +72,28 @@ ufsfree free size in kB
|
|||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
|
|
||||||
// global file system pointer
|
// Global file system pointer
|
||||||
FS *ufsp;
|
FS *ufsp;
|
||||||
// flash file system pointer on esp32
|
// Flash file system pointer
|
||||||
FS *ffsp;
|
FS *ffsp;
|
||||||
// local pointer for file managment
|
// Local pointer for file managment
|
||||||
FS *dfsp;
|
FS *dfsp;
|
||||||
|
|
||||||
char ufs_path[48];
|
char ufs_path[48];
|
||||||
File ufs_upload_file;
|
File ufs_upload_file;
|
||||||
uint8_t ufs_dir;
|
uint8_t ufs_dir;
|
||||||
// 0 = none, 1 = SD, 2 = ffat, 3 = littlefs
|
// 0 = None, 1 = SD, 2 = ffat, 3 = littlefs
|
||||||
uint8_t ufs_type;
|
uint8_t ufs_type;
|
||||||
uint8_t ffs_type;
|
uint8_t ffs_type;
|
||||||
bool download_busy;
|
bool download_busy;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
// init flash file system
|
// Init flash file system
|
||||||
void UfsInitOnce(void) {
|
void UfsInitOnce(void) {
|
||||||
ufs_type = 0;
|
ufs_type = 0;
|
||||||
ffsp = 0;
|
ffsp = 0;
|
||||||
@ -130,21 +133,13 @@ void UfsInitOnce(void) {
|
|||||||
void UfsInit(void) {
|
void UfsInit(void) {
|
||||||
UfsInitOnce();
|
UfsInitOnce();
|
||||||
if (ufs_type) {
|
if (ufs_type) {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: Type %d mounted with %d kB free"), ufs_type, UfsInfo(1, 0));
|
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: FlashFS mounted with %d kB free"), UfsInfo(1, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_SDCARD
|
#ifdef USE_SDCARD
|
||||||
void UfsCheckSDCardInit(void) {
|
void UfsCheckSDCardInit(void) {
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
if (PinUsed(GPIO_SPI_CLK) && PinUsed(GPIO_SPI_MOSI) && PinUsed(GPIO_SPI_MISO)) {
|
|
||||||
#endif // ESP8266
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
if (TasmotaGlobal.spi_enabled) {
|
if (TasmotaGlobal.spi_enabled) {
|
||||||
#endif // ESP32
|
|
||||||
int8_t cs = SDCARD_CS_PIN;
|
int8_t cs = SDCARD_CS_PIN;
|
||||||
if (PinUsed(GPIO_SDCARD_CS)) {
|
if (PinUsed(GPIO_SDCARD_CS)) {
|
||||||
cs = Pin(GPIO_SDCARD_CS);
|
cs = Pin(GPIO_SDCARD_CS);
|
||||||
@ -172,10 +167,10 @@ void UfsCheckSDCardInit(void) {
|
|||||||
// make sd card the global filesystem
|
// make sd card the global filesystem
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
// on esp8266 sdcard info takes several seconds !!!, so we ommit it here
|
// on esp8266 sdcard info takes several seconds !!!, so we ommit it here
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCARD mounted"));
|
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCard mounted"));
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCARD mounted with %d kB free"), UfsInfo(1, 0));
|
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCard mounted with %d kB free"), UfsInfo(1, 0));
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,38 +269,12 @@ uint8_t UfsReject(char *name) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format number with thousand marker - Not international as '.' is decimal on most countries
|
|
||||||
void UfsForm1000(uint32_t number, char *dp, char sc) {
|
|
||||||
char str[32];
|
|
||||||
sprintf(str, "%d", number);
|
|
||||||
char *sp = str;
|
|
||||||
uint32_t inum = strlen(sp)/3;
|
|
||||||
uint32_t fnum = strlen(sp)%3;
|
|
||||||
if (!fnum) { inum--; }
|
|
||||||
for (uint32_t count = 0; count <= inum; count++) {
|
|
||||||
if (fnum) {
|
|
||||||
memcpy(dp, sp, fnum);
|
|
||||||
dp += fnum;
|
|
||||||
sp += fnum;
|
|
||||||
fnum = 0;
|
|
||||||
} else {
|
|
||||||
memcpy(dp, sp, 3);
|
|
||||||
dp += 3;
|
|
||||||
sp += 3;
|
|
||||||
}
|
|
||||||
if (count != inum) {
|
|
||||||
*dp++ = sc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*dp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Tfs low level functions
|
* Tfs low level functions
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
bool TfsFileExists(const char *fname){
|
bool TfsFileExists(const char *fname){
|
||||||
if (!ufs_type) { return false; }
|
if (!ffs_type) { return false; }
|
||||||
|
|
||||||
bool yes = ffsp->exists(fname);
|
bool yes = ffsp->exists(fname);
|
||||||
if (!yes) {
|
if (!yes) {
|
||||||
@ -315,7 +284,7 @@ bool TfsFileExists(const char *fname){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
|
bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
|
||||||
if (!ufs_type) { return false; }
|
if (!ffs_type) { return false; }
|
||||||
|
|
||||||
File file = ffsp->open(fname, "w");
|
File file = ffsp->open(fname, "w");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@ -329,7 +298,7 @@ bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) {
|
bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) {
|
||||||
if (!ufs_type) { return false; }
|
if (!ffs_type) { return false; }
|
||||||
|
|
||||||
File file = ffsp->open(fname, "w");
|
File file = ffsp->open(fname, "w");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@ -345,7 +314,7 @@ bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
|
bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
|
||||||
if (!ufs_type) { return false; }
|
if (!ffs_type) { return false; }
|
||||||
if (!TfsFileExists(fname)) { return false; }
|
if (!TfsFileExists(fname)) { return false; }
|
||||||
|
|
||||||
File file = ffsp->open(fname, "r");
|
File file = ffsp->open(fname, "r");
|
||||||
@ -360,7 +329,7 @@ bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TfsDeleteFile(const char *fname) {
|
bool TfsDeleteFile(const char *fname) {
|
||||||
if (!ufs_type) { return false; }
|
if (!ffs_type) { return false; }
|
||||||
|
|
||||||
if (!ffsp->remove(fname)) {
|
if (!ffsp->remove(fname)) {
|
||||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Delete failed"));
|
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Delete failed"));
|
||||||
@ -380,24 +349,48 @@ void (* const kUFSCommand[])(void) PROGMEM = {
|
|||||||
&UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete};
|
&UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete};
|
||||||
|
|
||||||
void UFSInfo(void) {
|
void UFSInfo(void) {
|
||||||
Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
|
Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
|
||||||
|
if (ffs_type && (ffs_type != ufs_type)) {
|
||||||
|
ResponseAppend_P(PSTR(",{\"Type\":%d,\"Size\":%d,\"Free\":%d}"), ffs_type, UfsInfo(0, 1), UfsInfo(1, 1));
|
||||||
|
}
|
||||||
|
ResponseJsonEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UFSType(void) {
|
void UFSType(void) {
|
||||||
ResponseCmndNumber(ufs_type);
|
if (ffs_type && (ffs_type != ufs_type)) {
|
||||||
|
Response_P(PSTR("{\"%s\":[%d,%d]}"), XdrvMailbox.command, ufs_type, ffs_type);
|
||||||
|
} else {
|
||||||
|
ResponseCmndNumber(ufs_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UFSSize(void) {
|
void UFSSize(void) {
|
||||||
ResponseCmndNumber(UfsInfo(0, 0));
|
if (ffs_type && (ffs_type != ufs_type)) {
|
||||||
|
Response_P(PSTR("{\"%s\":[%d,%d]}"), XdrvMailbox.command, UfsInfo(0, 0), UfsInfo(0, 1));
|
||||||
|
} else {
|
||||||
|
ResponseCmndNumber(UfsInfo(0, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UFSFree(void) {
|
void UFSFree(void) {
|
||||||
ResponseCmndNumber(UfsInfo(1, 0));
|
if (ffs_type && (ffs_type != ufs_type)) {
|
||||||
|
Response_P(PSTR("{\"%s\":[%d,%d]}"), XdrvMailbox.command, UfsInfo(1, 0), UfsInfo(1, 1));
|
||||||
|
} else {
|
||||||
|
ResponseCmndNumber(UfsInfo(1, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UFSDelete(void) {
|
void UFSDelete(void) {
|
||||||
|
// UfsDelete sdcard or flashfs file if only one of them available
|
||||||
|
// UfsDelete2 flashfs file if available
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
if (!TfsDeleteFile(XdrvMailbox.data)) {
|
bool result = false;
|
||||||
|
if (ffs_type && (ffs_type != ufs_type) && (2 == XdrvMailbox.index)) {
|
||||||
|
result = TfsDeleteFile(XdrvMailbox.data);
|
||||||
|
} else {
|
||||||
|
result = (ufs_type && ufsp->remove(XdrvMailbox.data));
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
ResponseCmndChar(D_JSON_FAILED);
|
ResponseCmndChar(D_JSON_FAILED);
|
||||||
} else {
|
} else {
|
||||||
ResponseCmndDone();
|
ResponseCmndDone();
|
||||||
@ -418,7 +411,7 @@ const char UFS_FORM_FILE_UPLOAD[] PROGMEM =
|
|||||||
"<div id='f1' name='f1' style='display:block;'>"
|
"<div id='f1' name='f1' style='display:block;'>"
|
||||||
"<fieldset><legend><b> " D_MANAGE_FILE_SYSTEM " </b></legend>";
|
"<fieldset><legend><b> " D_MANAGE_FILE_SYSTEM " </b></legend>";
|
||||||
const char UFS_FORM_FILE_UPGc[] PROGMEM =
|
const char UFS_FORM_FILE_UPGc[] PROGMEM =
|
||||||
"<div style='text-align:left;color:#%06x;'>" D_FS_SIZE " %s kB - " D_FS_FREE " %s kB";
|
"<div style='text-align:left;color:#%06x;'>" D_FS_SIZE " %s MB - " D_FS_FREE " %s MB";
|
||||||
|
|
||||||
const char UFS_FORM_FILE_UPGc1[] PROGMEM =
|
const char UFS_FORM_FILE_UPGc1[] PROGMEM =
|
||||||
" <a href='http://%s/ufsd?dir=%d'>%s</a>";
|
" <a href='http://%s/ufsd?dir=%d'>%s</a>";
|
||||||
@ -451,7 +444,6 @@ const char UFS_FORM_SDC_HREFdel[] PROGMEM =
|
|||||||
"<a href=http://%s/ufsd?delete=%s/%s>🔥</a>"; // 🔥
|
"<a href=http://%s/ufsd?delete=%s/%s>🔥</a>"; // 🔥
|
||||||
#endif // GUI_TRASH_FILE
|
#endif // GUI_TRASH_FILE
|
||||||
|
|
||||||
|
|
||||||
void UfsDirectory(void) {
|
void UfsDirectory(void) {
|
||||||
if (!HttpCheckPriviledgedAccess()) { return; }
|
if (!HttpCheckPriviledgedAccess()) { return; }
|
||||||
|
|
||||||
@ -461,8 +453,6 @@ void UfsDirectory(void) {
|
|||||||
|
|
||||||
strcpy(ufs_path, "/");
|
strcpy(ufs_path, "/");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (Webserver->hasArg("download")) {
|
if (Webserver->hasArg("download")) {
|
||||||
String stmp = Webserver->arg("download");
|
String stmp = Webserver->arg("download");
|
||||||
char *cp = (char*)stmp.c_str();
|
char *cp = (char*)stmp.c_str();
|
||||||
@ -494,15 +484,14 @@ void UfsDirectory(void) {
|
|||||||
WSContentSendStyle();
|
WSContentSendStyle();
|
||||||
WSContentSend_P(UFS_FORM_FILE_UPLOAD);
|
WSContentSend_P(UFS_FORM_FILE_UPLOAD);
|
||||||
|
|
||||||
char ts[16];
|
char ts[FLOATSZ];
|
||||||
char fs[16];
|
dtostrfd((float)UfsInfo(0, ufs_dir == 2 ? 1:0) / 1000, 3, ts);
|
||||||
UfsForm1000(UfsInfo(0, ufs_dir == 2 ? 1:0), ts, '.');
|
char fs[FLOATSZ];
|
||||||
UfsForm1000(UfsInfo(1, ufs_dir == 2 ? 1:0), fs, '.');
|
dtostrfd((float)UfsInfo(1, ufs_dir == 2 ? 1:0) / 1000, 3, fs);
|
||||||
|
WSContentSend_PD(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs);
|
||||||
WSContentSend_P(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs);
|
|
||||||
|
|
||||||
if (ufs_dir) {
|
if (ufs_dir) {
|
||||||
WSContentSend_P(UFS_FORM_FILE_UPGc1, WiFi.localIP().toString().c_str(),ufs_dir == 1 ? 2:1, ufs_dir == 1 ? "SDCard":"FlashFS");
|
WSContentSend_P(UFS_FORM_FILE_UPGc1, WiFi.localIP().toString().c_str(), (ufs_dir == 1)?2:1, (ufs_dir == 1)?PSTR("SDCard"):PSTR("FlashFS"));
|
||||||
}
|
}
|
||||||
WSContentSend_P(UFS_FORM_FILE_UPGc2);
|
WSContentSend_P(UFS_FORM_FILE_UPGc2);
|
||||||
|
|
||||||
|
@ -416,7 +416,123 @@ bool (* const xdrv_func_ptr[])(uint8_t) = { // Driver Function Pointers
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XDRV_99
|
#ifdef XDRV_99
|
||||||
&Xdrv99
|
&Xdrv99,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_100
|
||||||
|
&Xdrv100,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_101
|
||||||
|
&Xdrv101,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_102
|
||||||
|
&Xdrv102,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_103
|
||||||
|
&Xdrv103,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_104
|
||||||
|
&Xdrv104,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_105
|
||||||
|
&Xdrv105,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_106
|
||||||
|
&Xdrv106,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_107
|
||||||
|
&Xdrv107,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_108
|
||||||
|
&Xdrv108,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_109
|
||||||
|
&Xdrv109,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_110
|
||||||
|
&Xdrv110,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_111
|
||||||
|
&Xdrv111,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_112
|
||||||
|
&Xdrv112,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_113
|
||||||
|
&Xdrv113,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_114
|
||||||
|
&Xdrv114,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_115
|
||||||
|
&Xdrv115,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_116
|
||||||
|
&Xdrv116,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_117
|
||||||
|
&Xdrv117,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_118
|
||||||
|
&Xdrv118,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_119
|
||||||
|
&Xdrv119,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_120
|
||||||
|
&Xdrv120,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_121
|
||||||
|
&Xdrv121,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_122
|
||||||
|
&Xdrv122,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_123
|
||||||
|
&Xdrv123,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_124
|
||||||
|
&Xdrv124,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_125
|
||||||
|
&Xdrv125,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_126
|
||||||
|
&Xdrv126,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_127
|
||||||
|
&Xdrv127,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_128
|
||||||
|
&Xdrv128
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -825,7 +941,123 @@ const uint8_t kXdrvList[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XDRV_99
|
#ifdef XDRV_99
|
||||||
XDRV_99
|
XDRV_99,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_100
|
||||||
|
Xdrv100,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_101
|
||||||
|
Xdrv101,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_102
|
||||||
|
Xdrv102,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_103
|
||||||
|
Xdrv103,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_104
|
||||||
|
Xdrv104,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_105
|
||||||
|
Xdrv105,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_106
|
||||||
|
Xdrv106,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_107
|
||||||
|
Xdrv107,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_108
|
||||||
|
Xdrv108,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_109
|
||||||
|
Xdrv109,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_110
|
||||||
|
Xdrv110,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_111
|
||||||
|
Xdrv111,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_112
|
||||||
|
Xdrv112,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_113
|
||||||
|
Xdrv113,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_114
|
||||||
|
Xdrv114,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_115
|
||||||
|
Xdrv115,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_116
|
||||||
|
Xdrv116,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_117
|
||||||
|
Xdrv117,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_118
|
||||||
|
Xdrv118,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_119
|
||||||
|
Xdrv119,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_120
|
||||||
|
Xdrv120,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_121
|
||||||
|
Xdrv121,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_122
|
||||||
|
Xdrv122,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_123
|
||||||
|
Xdrv123,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_124
|
||||||
|
Xdrv124,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_125
|
||||||
|
Xdrv125,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_126
|
||||||
|
Xdrv126,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_127
|
||||||
|
Xdrv127,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDRV_128
|
||||||
|
Xdrv128
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +87,71 @@ bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XDSP_16
|
#ifdef XDSP_16
|
||||||
&Xdsp16
|
&Xdsp16,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_17
|
||||||
|
&Xdsp17,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_18
|
||||||
|
&Xdsp18,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_19
|
||||||
|
&Xdsp19,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_20
|
||||||
|
&Xdsp20,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_21
|
||||||
|
&Xdsp21,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_22
|
||||||
|
&Xdsp22,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_23
|
||||||
|
&Xdsp23,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_24
|
||||||
|
&Xdsp24,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_25
|
||||||
|
&Xdsp25,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_26
|
||||||
|
&Xdsp26,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_27
|
||||||
|
&Xdsp27,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_28
|
||||||
|
&Xdsp28,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_29
|
||||||
|
&Xdsp29,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_30
|
||||||
|
&Xdsp30,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_31
|
||||||
|
&Xdsp31,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XDSP_32
|
||||||
|
&Xdsp32
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -279,16 +279,13 @@ void ESP32Init() {
|
|||||||
|
|
||||||
if (TasmotaGlobal.global_state.wifi_down) { return; }
|
if (TasmotaGlobal.global_state.wifi_down) { return; }
|
||||||
|
|
||||||
|
TasmotaGlobal.wifi_stay_asleep = true;
|
||||||
if (WiFi.getSleep() == false) {
|
if (WiFi.getSleep() == false) {
|
||||||
if (0 == Settings.flag3.sleep_normal) {
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: Put WiFi modem in sleep mode"),"BLE");
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: About to restart to put WiFi modem in sleep mode"),"BLE");
|
WiFi.setSleep(true); // Sleep
|
||||||
Settings.flag3.sleep_normal = 1; // SetOption60 - Enable normal sleep instead of dynamic sleep
|
|
||||||
TasmotaGlobal.restart_flag = 2;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: Initializing Blueetooth..."),"BLE");
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: Initializing Bluetooth..."),"BLE");
|
||||||
|
|
||||||
if (!ESP32BLE.mode.init) {
|
if (!ESP32BLE.mode.init) {
|
||||||
NimBLEDevice::init("");
|
NimBLEDevice::init("");
|
||||||
|
@ -589,17 +589,17 @@ int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){
|
|||||||
MI32_ReverseMAC(packet->MAC);
|
MI32_ReverseMAC(packet->MAC);
|
||||||
uint8_t _bindkey[16] = {0x0};
|
uint8_t _bindkey[16] = {0x0};
|
||||||
bool foundNoKey = true;
|
bool foundNoKey = true;
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: search key for MAC: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Search key for MAC: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
|
||||||
for(uint32_t i=0; i<MIBLEbindKeys.size(); i++){
|
for(uint32_t i=0; i<MIBLEbindKeys.size(); i++){
|
||||||
if(memcmp(packet->MAC,MIBLEbindKeys[i].MAC,sizeof(packet->MAC))==0){
|
if(memcmp(packet->MAC,MIBLEbindKeys[i].MAC,sizeof(packet->MAC))==0){
|
||||||
memcpy(_bindkey,MIBLEbindKeys[i].key,sizeof(_bindkey));
|
memcpy(_bindkey,MIBLEbindKeys[i].key,sizeof(_bindkey));
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: decryption Key found"));
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Decryption Key found"));
|
||||||
foundNoKey = false;
|
foundNoKey = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(foundNoKey){
|
if(foundNoKey){
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: no Key found !!"));
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: No Key found !!"));
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +619,7 @@ int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){
|
|||||||
|
|
||||||
ret = br_ccm_check_tag(&ctx, &tag);
|
ret = br_ccm_check_tag(&ctx, &tag);
|
||||||
|
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: Err:%i, Decrypted : %02x %02x %02x %02x %02x "), ret, packet->payload[1],packet->payload[2],packet->payload[3],packet->payload[4],packet->payload[5]);
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Err:%i, Decrypted : %02x %02x %02x %02x %02x "), ret, packet->payload[1],packet->payload[2],packet->payload[3],packet->payload[4],packet->payload[5]);
|
||||||
return ret-1;
|
return ret-1;
|
||||||
}
|
}
|
||||||
#endif // USE_MI_DECRYPTION
|
#endif // USE_MI_DECRYPTION
|
||||||
@ -660,7 +660,7 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter)
|
|||||||
bool _success = false;
|
bool _success = false;
|
||||||
for (uint32_t i=0;i<MI32_TYPES;i++){ // i < sizeof(kMI32DeviceID) gives compiler warning
|
for (uint32_t i=0;i<MI32_TYPES;i++){ // i < sizeof(kMI32DeviceID) gives compiler warning
|
||||||
if(_type == kMI32DeviceID[i]){
|
if(_type == kMI32DeviceID[i]){
|
||||||
DEBUG_SENSOR_LOG(PSTR("MI32: ID is type %u"), i);
|
DEBUG_SENSOR_LOG(PSTR("M32: ID is type %u"), i);
|
||||||
_type = i+1;
|
_type = i+1;
|
||||||
_success = true;
|
_success = true;
|
||||||
}
|
}
|
||||||
@ -779,26 +779,23 @@ void MI32PreInit(void) {
|
|||||||
MI32.option.showRSSI = 1;
|
MI32.option.showRSSI = 1;
|
||||||
MI32.option.ignoreBogusBattery = 1; // from advertisements
|
MI32.option.ignoreBogusBattery = 1; // from advertisements
|
||||||
MI32.option.holdBackFirstAutodiscovery = 1;
|
MI32.option.holdBackFirstAutodiscovery = 1;
|
||||||
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: pre-init"));
|
AddLog_P(LOG_LEVEL_INFO,PSTR("M32: pre-init"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MI32Init(void) {
|
void MI32Init(void) {
|
||||||
if (MI32.mode.init) { return; }
|
if (MI32.mode.init) { return; }
|
||||||
|
|
||||||
if (TasmotaGlobal.global_state.wifi_down) { return; }
|
if (TasmotaGlobal.global_state.wifi_down) { return; }
|
||||||
|
|
||||||
|
TasmotaGlobal.wifi_stay_asleep = true;
|
||||||
if (WiFi.getSleep() == false) {
|
if (WiFi.getSleep() == false) {
|
||||||
// AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: WiFi modem not in sleep mode, BLE cannot start yet"));
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Put WiFi modem in sleep mode"));
|
||||||
if (0 == Settings.flag3.sleep_normal) {
|
WiFi.setSleep(true); // Sleep
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: About to restart to put WiFi modem in sleep mode"));
|
|
||||||
Settings.flag3.sleep_normal = 1; // SetOption60 - Enable normal sleep instead of dynamic sleep
|
|
||||||
TasmotaGlobal.restart_flag = 2;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MI32.mode.init) {
|
if (!MI32.mode.init) {
|
||||||
NimBLEDevice::init("");
|
NimBLEDevice::init("");
|
||||||
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: init BLE device"));
|
AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Init BLE device"));
|
||||||
MI32.mode.canScan = 1;
|
MI32.mode.canScan = 1;
|
||||||
MI32.mode.init = 1;
|
MI32.mode.init = 1;
|
||||||
MI32.period = Settings.tele_period;
|
MI32.period = Settings.tele_period;
|
||||||
@ -1286,7 +1283,7 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(decryptRet!=0){
|
if(decryptRet!=0){
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: decryption failed with error: %d"),decryptRet);
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Decryption failed with error: %d"),decryptRet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif //USE_MI_DECRYPTION
|
#endif //USE_MI_DECRYPTION
|
||||||
@ -1459,7 +1456,7 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int RSSI
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUG_SENSOR_LOG(PSTR("MI32: unexpected CGD1-packet"));
|
DEBUG_SENSOR_LOG(PSTR("M32: Unexpected CGD1-packet"));
|
||||||
}
|
}
|
||||||
if(MIBLEsensors[_slot].eventType.raw == 0) return;
|
if(MIBLEsensors[_slot].eventType.raw == 0) return;
|
||||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||||
@ -1491,7 +1488,7 @@ void MI32ParseResponse(char *buf, uint16_t bufsize, uint8_t addr[6], int RSSI) {
|
|||||||
* @param UUID
|
* @param UUID
|
||||||
*/
|
*/
|
||||||
void MI32ParseGenericBeacon(uint8_t* payload, size_t payloadLength, uint16_t* CID, uint16_t*SVC, uint16_t* UUID){
|
void MI32ParseGenericBeacon(uint8_t* payload, size_t payloadLength, uint16_t* CID, uint16_t*SVC, uint16_t* UUID){
|
||||||
AddLog_P(LOG_LEVEL_DEBUG_MORE,PSTR("MI32: Beacon:____________"));
|
AddLog_P(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Beacon:____________"));
|
||||||
for (uint32_t i = 0; i<payloadLength;){
|
for (uint32_t i = 0; i<payloadLength;){
|
||||||
uint32_t ADtype = payload[i+1];
|
uint32_t ADtype = payload[i+1];
|
||||||
uint32_t offset = payload[i];
|
uint32_t offset = payload[i];
|
||||||
@ -1549,13 +1546,13 @@ void MI32HandleGenericBeacon(uint8_t* payload, size_t payloadLength, int RSSI, u
|
|||||||
}
|
}
|
||||||
// else handle scan
|
// else handle scan
|
||||||
if(MIBLEscanResult.size()>19) {
|
if(MIBLEscanResult.size()>19) {
|
||||||
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: Scan buffer full"));
|
AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Scan buffer full"));
|
||||||
MI32.state.beaconScanCounter = 1;
|
MI32.state.beaconScanCounter = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(auto _scanResult : MIBLEscanResult){
|
for(auto _scanResult : MIBLEscanResult){
|
||||||
if(memcmp(addr,_scanResult.MAC,6)==0){
|
if(memcmp(addr,_scanResult.MAC,6)==0){
|
||||||
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: known device"));
|
// AddLog_P(LOG_LEVEL_INFO,PSTR("M32: known device"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1585,12 +1582,12 @@ void MI32addBeacon(uint8_t index, char* data){
|
|||||||
_new.time = 0;
|
_new.time = 0;
|
||||||
if(memcmp(_empty,_new.MAC,6) == 0){
|
if(memcmp(_empty,_new.MAC,6) == 0){
|
||||||
_new.active = false;
|
_new.active = false;
|
||||||
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: beacon%u deactivated"), index);
|
AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Beacon%u deactivated"), index);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
_new.active = true;
|
_new.active = true;
|
||||||
MI32.mode.activeBeacon = 1;
|
MI32.mode.activeBeacon = 1;
|
||||||
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: beacon added with MAC: %s"), _MAC);
|
AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Beacon added with MAC: %s"), _MAC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1845,7 +1842,7 @@ void CmndMi32Time(void) {
|
|||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
if (MIBLEsensors.size() > XdrvMailbox.payload) {
|
if (MIBLEsensors.size() > XdrvMailbox.payload) {
|
||||||
if ((LYWSD02 == MIBLEsensors[XdrvMailbox.payload].type) || (MHOC303 == MIBLEsensors[XdrvMailbox.payload].type)) {
|
if ((LYWSD02 == MIBLEsensors[XdrvMailbox.payload].type) || (MHOC303 == MIBLEsensors[XdrvMailbox.payload].type)) {
|
||||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("MI32: will set Time"));
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("M32: Will set Time"));
|
||||||
MI32.state.sensor = XdrvMailbox.payload;
|
MI32.state.sensor = XdrvMailbox.payload;
|
||||||
MI32.mode.canScan = 0;
|
MI32.mode.canScan = 0;
|
||||||
MI32.mode.canConnect = 0;
|
MI32.mode.canConnect = 0;
|
||||||
@ -1875,7 +1872,7 @@ void CmndMi32Unit(void) {
|
|||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
if (MIBLEsensors.size() > XdrvMailbox.payload) {
|
if (MIBLEsensors.size() > XdrvMailbox.payload) {
|
||||||
if ((LYWSD02 == MIBLEsensors[XdrvMailbox.payload].type) || (MHOC303 == MIBLEsensors[XdrvMailbox.payload].type)) {
|
if ((LYWSD02 == MIBLEsensors[XdrvMailbox.payload].type) || (MHOC303 == MIBLEsensors[XdrvMailbox.payload].type)) {
|
||||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: will set Unit"));
|
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Will set Unit"));
|
||||||
MI32.state.sensor = XdrvMailbox.payload;
|
MI32.state.sensor = XdrvMailbox.payload;
|
||||||
MI32.mode.canScan = 0;
|
MI32.mode.canScan = 0;
|
||||||
MI32.mode.canConnect = 0;
|
MI32.mode.canConnect = 0;
|
||||||
@ -1925,11 +1922,11 @@ void CmndMi32Block(void){
|
|||||||
switch (XdrvMailbox.index) {
|
switch (XdrvMailbox.index) {
|
||||||
case 0:
|
case 0:
|
||||||
MIBLEBlockList.clear();
|
MIBLEBlockList.clear();
|
||||||
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: size of ilist: %u"), MIBLEBlockList.size());
|
// AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Size of ilist: %u"), MIBLEBlockList.size());
|
||||||
ResponseCmndIdxChar(PSTR("block list cleared"));
|
ResponseCmndIdxChar(PSTR("Block list cleared"));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
ResponseCmndIdxChar(PSTR("show block list"));
|
ResponseCmndIdxChar(PSTR("Show block list"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1955,7 +1952,7 @@ void CmndMi32Block(void){
|
|||||||
ResponseCmndIdxChar(XdrvMailbox.data);
|
ResponseCmndIdxChar(XdrvMailbox.data);
|
||||||
MI32removeMIBLEsensor(_MACasBytes.buf);
|
MI32removeMIBLEsensor(_MACasBytes.buf);
|
||||||
}
|
}
|
||||||
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: size of ilist: %u"), MIBLEBlockList.size());
|
// AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Size of ilist: %u"), MIBLEBlockList.size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,143 +20,310 @@
|
|||||||
|
|
||||||
#ifdef USE_I2C
|
#ifdef USE_I2C
|
||||||
#ifdef USE_SEESAW_SOIL
|
#ifdef USE_SEESAW_SOIL
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* SEESAW_SOIL - Capacitance & Temperature Sensor
|
* SEESAW_SOIL - Capacitice Soil Moisture & Temperature Sensor
|
||||||
*
|
*
|
||||||
* I2C Address: 0x36, 0x37, 0x38, 0x39
|
* I2C Address: 0x36, 0x37, 0x38, 0x39
|
||||||
*
|
*
|
||||||
|
* This version of the driver replaces all delay loops by a state machine. So the number
|
||||||
|
* of instruction cycles consumed has been reduced dramatically. The sensors are reset,
|
||||||
|
* detected, commanded and read all at once. So the reading times won't increase with the
|
||||||
|
* number of sensors attached. The detection of sensors does not happen in FUNC_INIT any
|
||||||
|
* more. All i2c handling happens in the 50ms state machine.
|
||||||
|
* The memory footprint has suffered a little bit from this redesign, naturally.
|
||||||
|
*
|
||||||
|
* Memory footprint: 1444 bytes flash / 68 bytes RAM
|
||||||
|
*
|
||||||
* NOTE: #define SEESAW_SOIL_PUBLISH enables immediate MQTT on soil moisture change
|
* NOTE: #define SEESAW_SOIL_PUBLISH enables immediate MQTT on soil moisture change
|
||||||
* otherwise the moisture value will only be emitted every TelePeriod
|
* otherwise the moisture value will only be emitted every TelePeriod
|
||||||
* #define SEESAW_SOIL_RAW enables displaying analog capacitance input in the
|
* #define SEESAW_SOIL_RAW enables displaying analog capacitance input in the
|
||||||
* web page for calibration purposes
|
* web page for calibration purposes
|
||||||
|
* #define SEESAW_SOIL_PERSISTENT_NAMING to get sensor names indexed by i2c address
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#define XSNS_81 81
|
#define XSNS_81 81
|
||||||
#define XI2C_56 56 // See I2CDEVICES.md
|
#define XI2C_56 56 // See I2CDEVICES.md
|
||||||
|
|
||||||
#include "Adafruit_seesaw.h"
|
#include "Adafruit_seesaw.h" // we only use definitions, no code
|
||||||
|
|
||||||
#define SEESAW_SOIL_MAX_SENSORS 4
|
#define SEESAW_SOIL_MAX_SENSORS 4
|
||||||
#define SEESAW_SOIL_START_ADDRESS 0x36
|
#define SEESAW_SOIL_START_ADDRESS 0x36
|
||||||
|
// I2C state machine
|
||||||
|
#define STATE_IDLE 0x00
|
||||||
|
#define STATE_RESET 0x01
|
||||||
|
#define STATE_INIT 0x02
|
||||||
|
#define STATE_DETECT 0x04
|
||||||
|
#define STATE_COMMAND_TEMP 0x08
|
||||||
|
#define STATE_READ_TEMP 0x10
|
||||||
|
#define STATE_COMMAND_MOIST 0x20
|
||||||
|
#define STATE_READ_MOIST 0x40
|
||||||
|
// I2C commands
|
||||||
|
#define COMMAND_RESET 0x01
|
||||||
|
#define COMMAND_ID 0x02
|
||||||
|
#define COMMAND_TEMP 0x04
|
||||||
|
#define COMMAND_MOIST 0x08
|
||||||
|
// I2C delays
|
||||||
|
#define DELAY_DETECT 1 // ms delay before reading ID
|
||||||
|
#define DELAY_TEMP 1 // ms delay between command and reading
|
||||||
|
#define DELAY_MOIST 5 // ms delay between command and reading
|
||||||
|
#define DELAY_RESET 500 // ms delay after slave reset
|
||||||
|
|
||||||
const char SeeSoilName[] = "SeeSoil"; // spaces not allowed for Homeassistant integration/mqtt topics
|
// Convert capacitance into a moisture.
|
||||||
uint8_t SeeSoilCount = 0; // global sensor count
|
// From observation, a free air reading is at 320, immersed in tap water, reading is 1014
|
||||||
|
// So let's make a scale that converts those (apparent) facts into a percentage
|
||||||
|
#define MAX_CAPACITANCE 1020.0f // subject to calibration
|
||||||
|
#define MIN_CAPACITANCE 320 // subject to calibration
|
||||||
|
#define CAP_TO_MOIST(c) ((max((int)(c),MIN_CAPACITANCE)-MIN_CAPACITANCE)/(MAX_CAPACITANCE-MIN_CAPACITANCE)*100)
|
||||||
|
|
||||||
struct SEESAW_SOIL {
|
struct SEESAW_SOIL {
|
||||||
Adafruit_seesaw *ss; // instance pointer
|
const char name[8] = "SeeSoil"; // spaces not allowed for Homeassistant integration/mqtt topics
|
||||||
uint16_t capacitance;
|
uint8_t count = 0; // global sensor count (0xFF = not initialized)
|
||||||
float temperature;
|
uint8_t state = STATE_IDLE; // current state
|
||||||
uint8_t address;
|
bool present = false; // driver active
|
||||||
} SeeSoil[SEESAW_SOIL_MAX_SENSORS];
|
} SeeSoil;
|
||||||
|
|
||||||
// Used to convert capacitance into a moisture.
|
struct SEESAW_SOIL_SNS {
|
||||||
// From observation, a free air reading is at 320
|
uint8_t address; // i2c address
|
||||||
// Immersed in tap water, reading is 1014
|
float moisture;
|
||||||
// Appears to be a 10-bit device, readings close to 1020
|
float temperature;
|
||||||
// So let's make a scale that converts those (apparent) facts into a percentage
|
#ifdef SEESAW_SOIL_RAW
|
||||||
#define MAX_CAPACITANCE 1020.0f // subject to calibration
|
uint16_t capacitance; // raw analog reading
|
||||||
#define MIN_CAPACITANCE 320 // subject to calibration
|
#endif // SEESAW_SOIL_RAW
|
||||||
#define CAP_TO_MOIST(c) ((max((int)(c),MIN_CAPACITANCE)-MIN_CAPACITANCE)/(MAX_CAPACITANCE-MIN_CAPACITANCE))
|
} SeeSoilSNS[SEESAW_SOIL_MAX_SENSORS];
|
||||||
|
|
||||||
/********************************************************************************************/
|
/*********************************************************************************************\
|
||||||
|
* i2c routines
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
void SEESAW_SOILDetect(void) {
|
void seeSoilInit(void) {
|
||||||
Adafruit_seesaw *SSptr=0;
|
for (int i = 0; i < SEESAW_SOIL_MAX_SENSORS; i++) {
|
||||||
|
|
||||||
for (uint32_t i = 0; i < SEESAW_SOIL_MAX_SENSORS; i++) {
|
|
||||||
int addr = SEESAW_SOIL_START_ADDRESS + i;
|
int addr = SEESAW_SOIL_START_ADDRESS + i;
|
||||||
if (!I2cSetDevice(addr)) { continue; }
|
if ( ! I2cSetDevice(addr) ) { continue; }
|
||||||
|
seeSoilCommand(COMMAND_RESET);
|
||||||
if (!SSptr) { // don't have an object,
|
|
||||||
SSptr = new Adafruit_seesaw(); // allocate one
|
|
||||||
}
|
|
||||||
if (SSptr->begin(addr)) {
|
|
||||||
SeeSoil[SeeSoilCount].ss = SSptr; // save copy of pointer
|
|
||||||
SSptr = 0; // mark that we took it
|
|
||||||
SeeSoil[SeeSoilCount].address = addr;
|
|
||||||
SeeSoil[SeeSoilCount].temperature = NAN;
|
|
||||||
SeeSoil[SeeSoilCount].capacitance = 0;
|
|
||||||
I2cSetActiveFound(SeeSoil[SeeSoilCount].address, SeeSoilName);
|
|
||||||
SeeSoilCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (SSptr) {
|
SeeSoil.state = STATE_RESET;
|
||||||
delete SSptr; // used object for detection, didn't find anything so we don't need this object
|
SeeSoil.present = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void seeSoilEvery50ms(void){ // i2c state machine
|
||||||
|
static uint32_t state_time;
|
||||||
|
|
||||||
|
uint32_t time_diff = millis() - state_time;
|
||||||
|
|
||||||
|
switch (SeeSoil.state) {
|
||||||
|
case STATE_RESET: // reset was just issued
|
||||||
|
SeeSoil.state = STATE_INIT;
|
||||||
|
break;
|
||||||
|
case STATE_INIT: // wait for sensors to settle
|
||||||
|
if (time_diff < DELAY_RESET) { return; }
|
||||||
|
seeSoilCommand(COMMAND_ID); // send hardware id commands
|
||||||
|
SeeSoil.state = STATE_DETECT;
|
||||||
|
break;
|
||||||
|
case STATE_DETECT: // detect sensors
|
||||||
|
if (time_diff < DELAY_DETECT) { return; }
|
||||||
|
seeSoilDetect();
|
||||||
|
SeeSoil.state=STATE_COMMAND_TEMP;
|
||||||
|
break;
|
||||||
|
case STATE_COMMAND_TEMP: // send temperature commands
|
||||||
|
seeSoilCommand(COMMAND_TEMP);
|
||||||
|
SeeSoil.state = STATE_READ_TEMP;
|
||||||
|
break;
|
||||||
|
case STATE_READ_TEMP:
|
||||||
|
if (time_diff < DELAY_TEMP) { return; }
|
||||||
|
seeSoilRead(COMMAND_TEMP); // read temperature values
|
||||||
|
SeeSoil.state = STATE_COMMAND_MOIST;
|
||||||
|
break;
|
||||||
|
case STATE_COMMAND_MOIST: // send moisture commands
|
||||||
|
seeSoilCommand(COMMAND_MOIST);
|
||||||
|
SeeSoil.state = STATE_READ_MOIST;
|
||||||
|
break;
|
||||||
|
case STATE_READ_MOIST:
|
||||||
|
if (time_diff < DELAY_MOIST) { return; }
|
||||||
|
seeSoilRead(COMMAND_MOIST); // read moisture values
|
||||||
|
SeeSoil.state = STATE_COMMAND_TEMP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state_time = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void seeSoilDetect(void) { // detect sensors
|
||||||
|
uint8_t buf;
|
||||||
|
|
||||||
|
SeeSoil.count = 0;
|
||||||
|
SeeSoil.present = false;
|
||||||
|
for (int i = 0; i < SEESAW_SOIL_MAX_SENSORS; i++) {
|
||||||
|
uint32_t addr = SEESAW_SOIL_START_ADDRESS + i;
|
||||||
|
if ( ! I2cSetDevice(addr)) { continue; }
|
||||||
|
if (1 != Wire.requestFrom((uint8_t) addr, (uint8_t) 1)) { continue; }
|
||||||
|
buf = (uint8_t) Wire.read();
|
||||||
|
if (buf != SEESAW_HW_ID_CODE) { // check hardware id
|
||||||
|
#ifdef DEBUG_SEESAW_SOIL
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SEE: HWID mismatch ADDR=%X, ID=%X"), addr, buf);
|
||||||
|
#endif // DEBUG_SEESAW_SOIL
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SeeSoilSNS[SeeSoil.count].address = addr;
|
||||||
|
SeeSoilSNS[SeeSoil.count].temperature = NAN;
|
||||||
|
SeeSoilSNS[SeeSoil.count].moisture = NAN;
|
||||||
|
#ifdef SEESAW_SOIL_RAW
|
||||||
|
SeeSoilSNS[SeeSoil.count].capacitance = 0; // raw analog reading
|
||||||
|
#endif // SEESAW_SOIL_RAW
|
||||||
|
I2cSetActiveFound(SeeSoilSNS[SeeSoil.count].address, SeeSoil.name);
|
||||||
|
SeeSoil.count++;
|
||||||
|
SeeSoil.present = true;
|
||||||
|
#ifdef DEBUG_SEESAW_SOIL
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SEE: FOUND sensor %u at %02X"), i, addr);
|
||||||
|
#endif // DEBUG_SEESAW_SOIL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SEESAW_SOILEverySecond(void) { // update sensor values and publish if changed
|
void seeSoilCommand(uint32_t command) { // issue commands to sensors
|
||||||
#ifdef SEESAW_SOIL_PUBLISH
|
uint8_t regLow;
|
||||||
uint32_t old_moist;
|
uint8_t regHigh = SEESAW_STATUS_BASE;
|
||||||
#endif // SEESAW_SOIL_PUBLISH
|
uint32_t count = SeeSoil.count;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < SeeSoilCount; i++) {
|
switch (command) {
|
||||||
SeeSoil[i].temperature = ConvertTemp(SeeSoil[i].ss->getTemp());
|
case COMMAND_RESET:
|
||||||
#ifdef SEESAW_SOIL_PUBLISH
|
count = SEESAW_SOIL_MAX_SENSORS;
|
||||||
old_moist = uint32_t (CAP_TO_MOIST(SeeSoil[i].capacitance)*100);
|
regLow = SEESAW_STATUS_SWRST;
|
||||||
#endif // SEESAW_SOIL_PUBLISH
|
break;
|
||||||
SeeSoil[i].capacitance = SeeSoil[i].ss->touchRead(0);
|
case COMMAND_ID:
|
||||||
#ifdef SEESAW_SOIL_PUBLISH
|
count = SEESAW_SOIL_MAX_SENSORS;
|
||||||
if (uint32_t (CAP_TO_MOIST(SeeSoil[i].capacitance)*100) != old_moist) {
|
regLow = SEESAW_STATUS_HW_ID;
|
||||||
Response_P(PSTR("{")); // send values to MQTT & rules
|
break;
|
||||||
SEESAW_SOILJson(i);
|
case COMMAND_TEMP:
|
||||||
ResponseJsonEnd();
|
regLow = SEESAW_STATUS_TEMP;
|
||||||
MqttPublishTeleSensor();
|
break;
|
||||||
|
case COMMAND_MOIST:
|
||||||
|
regHigh = SEESAW_TOUCH_BASE;
|
||||||
|
regLow = SEESAW_TOUCH_CHANNEL_OFFSET;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef DEBUG_SEESAW_SOIL
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SEE: ILL CMD:%02X"), command);
|
||||||
|
#endif // DEBUG_SEESAW_SOIL
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
uint32_t addr = (command & (COMMAND_RESET|COMMAND_ID)) ? SEESAW_SOIL_START_ADDRESS + i : SeeSoilSNS[i].address;
|
||||||
|
Wire.beginTransmission((uint8_t) addr);
|
||||||
|
Wire.write((uint8_t) regHigh);
|
||||||
|
Wire.write((uint8_t) regLow);
|
||||||
|
uint32_t err = Wire.endTransmission();
|
||||||
|
#ifdef DEBUG_SEESAW_SOIL
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SEE: SNS=%u ADDR=%02X CMD=%02X ERR=%u"), i, addr, command, err);
|
||||||
|
#endif // DEBUG_SEESAW_SOIL
|
||||||
}
|
}
|
||||||
#endif // SEESAW_SOIL_PUBLISH
|
}
|
||||||
|
|
||||||
|
void seeSoilRead(uint32_t command) { // read values from sensors
|
||||||
|
uint8_t buf[4];
|
||||||
|
uint32_t num;
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
num = (command == COMMAND_TEMP) ? 4 : 2; // response size in bytes
|
||||||
|
|
||||||
|
for (int i = 0; i < SeeSoil.count; i++) { // for all sensors
|
||||||
|
if (num != Wire.requestFrom((uint8_t) SeeSoilSNS[i].address, (uint8_t) num)) { continue; }
|
||||||
|
bzero(buf, sizeof(buf));
|
||||||
|
for (int b = 0; b < num; b++) {
|
||||||
|
buf[b] = (uint8_t) Wire.read();
|
||||||
|
}
|
||||||
|
if (command == COMMAND_TEMP) {
|
||||||
|
ret = ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) |
|
||||||
|
((uint32_t)buf[2] << 8) | (uint32_t)buf[3];
|
||||||
|
SeeSoilSNS[i].temperature = ConvertTemp((1.0 / (1UL << 16)) * ret);
|
||||||
|
} else { // COMMAND_MOIST
|
||||||
|
ret = (uint32_t)buf[0] << 8 | (uint32_t)buf[1];
|
||||||
|
SeeSoilSNS[i].moisture = CAP_TO_MOIST(ret);
|
||||||
|
#ifdef SEESAW_SOIL_RAW
|
||||||
|
SeeSoilSNS[i].capacitance = ret;
|
||||||
|
#endif // SEESAW_SOIL_RAW
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_SEESAW_SOIL
|
||||||
|
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SEE: READ #%u ADDR=%02X NUM=%u RET=%X"), i, SeeSoilSNS[i].address, num, ret);
|
||||||
|
#endif // DEBUG_SEESAW_SOIL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SEESAW_SOILShow(bool json) {
|
/*********************************************************************************************\
|
||||||
|
* JSON routines
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef SEESAW_SOIL_PUBLISH
|
||||||
|
void seeSoilEverySecond(void) { // update sensor values and publish if changed
|
||||||
|
static uint16_t old_moist[SEESAW_SOIL_MAX_SENSORS];
|
||||||
|
static bool firstcall = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < SeeSoil.count; i++) {
|
||||||
|
if (firstcall) { firstcall = false; }
|
||||||
|
else {
|
||||||
|
if ((uint32_t) SeeSoilSNS[i].moisture != old_moist[i]) {
|
||||||
|
Response_P(PSTR("{")); // send values to MQTT & rules
|
||||||
|
seeSoilJson(i);
|
||||||
|
ResponseJsonEnd();
|
||||||
|
MqttPublishTeleSensor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_moist[i] = (uint32_t) SeeSoilSNS[i].moisture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // SEESAW_SOIL_PUBLISH
|
||||||
|
|
||||||
|
void seeSoilShow(bool json) {
|
||||||
char temperature[FLOATSZ];
|
char temperature[FLOATSZ];
|
||||||
char sensor_name[sizeof(SeeSoilName) + 3];
|
char sensor_name[sizeof(SeeSoil.name) + 3];
|
||||||
|
|
||||||
for (uint32_t i = 0; i < SeeSoilCount; i++) {
|
for (uint32_t i = 0; i < SeeSoil.count; i++) {
|
||||||
dtostrfd(SeeSoil[i].temperature, Settings.flag2.temperature_resolution, temperature);
|
dtostrfd(SeeSoilSNS[i].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||||
SEESAW_SOILName(i, sensor_name, sizeof(sensor_name));
|
seeSoilName(i, sensor_name, sizeof(sensor_name));
|
||||||
if (json) {
|
if (json) {
|
||||||
ResponseAppend_P(PSTR(",")); // compose tele json
|
ResponseAppend_P(PSTR(",")); // compose tele json
|
||||||
SEESAW_SOILJson(i);
|
seeSoilJson(i);
|
||||||
if (0 == TasmotaGlobal.tele_period) {
|
if (0 == TasmotaGlobal.tele_period) {
|
||||||
#ifdef USE_DOMOTICZ
|
#ifdef USE_DOMOTICZ
|
||||||
DomoticzTempHumPressureSensor(SeeSoil[i].temperature, CAP_TO_MOIST(SeeSoil[i].capacitance)*100, -42.0f);
|
DomoticzTempHumPressureSensor(SeeSoilSNS[i].temperature, SeeSoilSNS[i].moisture, -42.0f);
|
||||||
#endif // USE_DOMOTICZ
|
#endif // USE_DOMOTICZ
|
||||||
#ifdef USE_KNX
|
#ifdef USE_KNX
|
||||||
KnxSensor(KNX_TEMPERATURE, SeeSoil[i].temperature);
|
KnxSensor(KNX_TEMPERATURE, SeeSoilSNS[i].temperature);
|
||||||
KnxSensor(KNX_HUMIDITY, CAP_TO_MOIST(SeeSoil[i].capacitance) * 100);
|
KnxSensor(KNX_HUMIDITY, SeeSoilSNS[i].moisture);
|
||||||
#endif // USE_KNX
|
#endif // USE_KNX
|
||||||
}
|
}
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
} else {
|
} else {
|
||||||
#ifdef SEESAW_SOIL_RAW
|
#ifdef SEESAW_SOIL_RAW
|
||||||
WSContentSend_PD(HTTP_SNS_ANALOG, sensor_name, 0, SeeSoil[i].capacitance); // dump raw value
|
WSContentSend_PD(HTTP_SNS_ANALOG, sensor_name, 0, SeeSoilSNS[i].capacitance);
|
||||||
#endif // SEESAW_SOIL_RAW
|
#endif // SEESAW_SOIL_RAW
|
||||||
WSContentSend_PD(HTTP_SNS_MOISTURE, sensor_name,
|
WSContentSend_PD(HTTP_SNS_MOISTURE, sensor_name, (uint32_t) SeeSoilSNS[i].moisture);
|
||||||
uint32_t (CAP_TO_MOIST(SeeSoil[i].capacitance)*100)); // web page formats as integer (%d) percent
|
|
||||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, temperature, TempUnit());
|
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, temperature, TempUnit());
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
}
|
}
|
||||||
} // for each sensor connected
|
} // for each sensor connected
|
||||||
}
|
}
|
||||||
|
|
||||||
void SEESAW_SOILJson(int no) { // common json
|
void seeSoilJson(int no) { // common json
|
||||||
char temperature[FLOATSZ];
|
char temperature[FLOATSZ];
|
||||||
char sensor_name[sizeof(SeeSoilName) + 3];
|
char sensor_name[sizeof(SeeSoil.name) + 3];
|
||||||
|
|
||||||
SEESAW_SOILName(no, sensor_name, sizeof(sensor_name));
|
seeSoilName(no, sensor_name, sizeof(sensor_name));
|
||||||
dtostrfd(SeeSoil[no].temperature, Settings.flag2.temperature_resolution, temperature);
|
dtostrfd(SeeSoilSNS[no].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||||
ResponseAppend_P(PSTR ("\"%s\":{\"" D_JSON_ID "\":\"%02X\",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_MOISTURE "\":%u}"),
|
ResponseAppend_P(PSTR ("\"%s\":{\"" D_JSON_ID "\":\"%02X\",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_MOISTURE "\":%u}"),
|
||||||
sensor_name, SeeSoil[no].address, temperature, uint32_t (CAP_TO_MOIST(SeeSoil[no].capacitance)*100));
|
sensor_name, SeeSoilSNS[no].address, temperature, (uint32_t) SeeSoilSNS[no].moisture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SEESAW_SOILName(int no, char *name, int len) // generates a sensor name
|
void seeSoilName(int no, char *name, int len) // generates a sensor name
|
||||||
{
|
{
|
||||||
if (SeeSoilCount > 1) {
|
#ifdef SEESAW_SOIL_PERSISTENT_NAMING
|
||||||
snprintf_P(name, len, PSTR("%s%c%u"), SeeSoilName, IndexSeparator(), no + 1);
|
snprintf_P(name, len, PSTR("%s%c%02X"), SeeSoil.name, IndexSeparator(), SeeSoilSNS[no].address);
|
||||||
|
#else
|
||||||
|
if (SeeSoil.count > 1) {
|
||||||
|
snprintf_P(name, len, PSTR("%s%c%u"), SeeSoil.name, IndexSeparator(), no + 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
strlcpy(name, SeeSoilName, len);
|
strlcpy(name, SeeSoil.name, len);
|
||||||
}
|
}
|
||||||
|
#endif // SEESAW_SOIL_PERSISTENT_NAMING
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
@ -169,19 +336,24 @@ bool Xsns81(uint8_t function)
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if (FUNC_INIT == function) {
|
if (FUNC_INIT == function) {
|
||||||
SEESAW_SOILDetect();
|
seeSoilInit();
|
||||||
}
|
}
|
||||||
else if (SeeSoilCount){
|
else if (SeeSoil.present){
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case FUNC_EVERY_SECOND:
|
case FUNC_EVERY_50_MSECOND:
|
||||||
SEESAW_SOILEverySecond();
|
seeSoilEvery50ms();
|
||||||
break;
|
break;
|
||||||
|
#ifdef SEESAW_SOIL_PUBLISH
|
||||||
|
case FUNC_EVERY_SECOND:
|
||||||
|
seeSoilEverySecond();
|
||||||
|
break;
|
||||||
|
#endif // SEESAW_SOIL_PUBLISH
|
||||||
case FUNC_JSON_APPEND:
|
case FUNC_JSON_APPEND:
|
||||||
SEESAW_SOILShow(1);
|
seeSoilShow(1);
|
||||||
break;
|
break;
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
case FUNC_WEB_SENSOR:
|
case FUNC_WEB_SENSOR:
|
||||||
SEESAW_SOILShow(0);
|
seeSoilShow(0);
|
||||||
break;
|
break;
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
}
|
}
|
||||||
|
@ -825,27 +825,144 @@ const uint8_t kXsnsList[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XSNS_99
|
#ifdef XSNS_99
|
||||||
XSNS_99
|
XSNS_99,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_100
|
||||||
|
XSNS_100,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_101
|
||||||
|
XSNS_101,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_102
|
||||||
|
XSNS_102,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_103
|
||||||
|
XSNS_103,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_104
|
||||||
|
XSNS_104,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_105
|
||||||
|
XSNS_105,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_106
|
||||||
|
XSNS_106,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_107
|
||||||
|
XSNS_107,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_108
|
||||||
|
XSNS_108,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_109
|
||||||
|
XSNS_109,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_110
|
||||||
|
XSNS_110,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_111
|
||||||
|
XSNS_111,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_112
|
||||||
|
XSNS_112,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_113
|
||||||
|
XSNS_113,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_114
|
||||||
|
XSNS_114,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_115
|
||||||
|
XSNS_115,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_116
|
||||||
|
XSNS_116,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_117
|
||||||
|
XSNS_117,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_118
|
||||||
|
XSNS_118,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_119
|
||||||
|
XSNS_119,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_120
|
||||||
|
XSNS_120,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_121
|
||||||
|
XSNS_121,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_122
|
||||||
|
XSNS_122,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_123
|
||||||
|
XSNS_123,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_124
|
||||||
|
XSNS_124,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_125
|
||||||
|
XSNS_125,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_126
|
||||||
|
XSNS_126,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_127
|
||||||
|
XSNS_127,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XSNS_128
|
||||||
|
XSNS_128
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
bool XsnsEnabled(uint32_t sns_index)
|
bool XsnsEnabled(uint32_t sns_index) {
|
||||||
{
|
|
||||||
if (sns_index < sizeof(kXsnsList)) {
|
if (sns_index < sizeof(kXsnsList)) {
|
||||||
#ifdef XFUNC_PTR_IN_ROM
|
#ifdef XFUNC_PTR_IN_ROM
|
||||||
uint32_t index = pgm_read_byte(kXsnsList + sns_index);
|
uint32_t index = pgm_read_byte(kXsnsList + sns_index);
|
||||||
#else
|
#else
|
||||||
uint32_t index = kXsnsList[sns_index];
|
uint32_t index = kXsnsList[sns_index];
|
||||||
#endif
|
#endif
|
||||||
return bitRead(Settings.sensors[index / 32], index % 32);
|
if (index < MAX_XSNS_DRIVERS) {
|
||||||
|
return bitRead(Settings.sensors[index / 32], index % 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XsnsSensorState(void)
|
void XsnsSensorState(void) {
|
||||||
{
|
|
||||||
ResponseAppend_P(PSTR("\"")); // Use string for enable/disable signal
|
ResponseAppend_P(PSTR("\"")); // Use string for enable/disable signal
|
||||||
for (uint32_t i = 0; i < sizeof(kXsnsList); i++) {
|
for (uint32_t i = 0; i < sizeof(kXsnsList); i++) {
|
||||||
#ifdef XFUNC_PTR_IN_ROM
|
#ifdef XFUNC_PTR_IN_ROM
|
||||||
@ -866,8 +983,7 @@ void XsnsSensorState(void)
|
|||||||
* Function call to all xsns
|
* Function call to all xsns
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index)
|
bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index) {
|
||||||
{
|
|
||||||
if (0 == xsns_present) {
|
if (0 == xsns_present) {
|
||||||
xsns_index = 0;
|
xsns_index = 0;
|
||||||
return false;
|
return false;
|
||||||
@ -891,8 +1007,7 @@ bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index)
|
|||||||
return xsns_func_ptr[xsns_index](Function);
|
return xsns_func_ptr[xsns_index](Function);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XsnsCall(uint8_t Function)
|
bool XsnsCall(uint8_t Function) {
|
||||||
{
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
DEBUG_TRACE_LOG(PSTR("SNS: %d"), Function);
|
DEBUG_TRACE_LOG(PSTR("SNS: %d"), Function);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user