mirror of https://github.com/arendst/Tasmota.git
commit
63f14adbf6
|
@ -9,6 +9,8 @@
|
|||
.clang_complete
|
||||
.gcc-flags.json
|
||||
.cache
|
||||
data
|
||||
unpacked_fs
|
||||
tasmota/user_config_override.h
|
||||
build
|
||||
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_PIN_STATE | x | 1 | 2 | | | At GPIO configuration
|
||||
FUNC_MODULE_INIT | x | 1 | | | 2 | Init module specific parameters
|
||||
FUNC_PRE_INIT | | 1 | | 2 | | Once GPIO have been established
|
||||
FUNC_MODULE_INIT | x | 3 | 1 | | 2 | Init module specific parameters
|
||||
FUNC_PRE_INIT | | 1 | 3 | 2 | | Once GPIO have been established
|
||||
FUNC_INIT | | 1 | 3 | 2 | | At end of initialisation
|
||||
FUNC_LOOP | | 1 | 2 | | | In main loop
|
||||
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_INIT | | x | | | | Once at end of MQTT connection
|
||||
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_SHOW_SENSOR | | x | | | | When FUNC_JSON_APPEND completes
|
||||
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_SET_CHANNELS | | 2 | | | 1 |
|
||||
FUNC_SET_SCHEME | | | | | x |
|
||||
FUNC_HOTPLUG_SCAN | | | x | | |
|
||||
FUNC_DEVICE_GROUP_ITEM | | x | | | |
|
||||
|
||||
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_PIN_STATE
|
||||
xsns - FUNC_PIN_STATE
|
||||
xsns - FUNC_MODULE_INIT
|
||||
xdrv - FUNC_MODULE_INIT
|
||||
xlgt - FUNC_MODULE_INIT
|
||||
xdrv - FUNC_PRE_INIT
|
||||
xnrg - FUNC_PRE_INIT
|
||||
xsns - FUNC_PRE_INIT
|
||||
SRC: Restart
|
||||
xdrv - FUNC_SET_POWER
|
||||
xsns - FUNC_SET_POWER
|
||||
xlgt - FUNC_SET_CHANNELS
|
||||
xdrv - FUNC_SET_DEVICE_POWER
|
||||
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 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
|
||||
- ESP32 support for TLS MQTT using BearSSL (same as ESP8266)
|
||||
|
||||
### Breaking Changed
|
||||
- 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
|
||||
- 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
|
||||
### Added
|
||||
|
|
|
@ -75,7 +75,7 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor
|
||||
51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | 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
|
||||
55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH 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``
|
||||
|
||||
### 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
|
||||
- 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)
|
||||
|
|
|
@ -28,14 +28,12 @@
|
|||
#undef WiFi
|
||||
#endif
|
||||
|
||||
void WiFiClass32::setSleepMode(int iSleepMode)
|
||||
{
|
||||
// WIFI_MODEM_SLEEP
|
||||
WiFi.setSleep(iSleepMode != WIFI_MODEM_SLEEP);
|
||||
void WiFiClass32::setSleepMode(int iSleepMode) {
|
||||
// WIFI_LIGHT_SLEEP and WIFI_MODEM_SLEEP
|
||||
WiFi.setSleep(iSleepMode != WIFI_NONE_SLEEP);
|
||||
}
|
||||
|
||||
int WiFiClass32::getPhyMode()
|
||||
{
|
||||
int WiFiClass32::getPhyMode() {
|
||||
int phy_mode = 0; // " BGNL"
|
||||
uint8_t protocol_bitmap;
|
||||
if (esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap) == ESP_OK) {
|
||||
|
@ -47,12 +45,10 @@ int WiFiClass32::getPhyMode()
|
|||
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;
|
||||
if (n > 19)
|
||||
p = WIFI_POWER_19_5dBm;
|
||||
|
@ -75,28 +71,23 @@ void WiFiClass32::setOutputPower(int n)
|
|||
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;
|
||||
return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel);
|
||||
}
|
||||
|
||||
void wifi_station_disconnect()
|
||||
{
|
||||
void wifi_station_disconnect() {
|
||||
// erase ap: empty ssid, ...
|
||||
WiFi.disconnect(true, true);
|
||||
}
|
||||
|
||||
void wifi_station_dhcpc_start()
|
||||
{
|
||||
void wifi_station_dhcpc_start() {
|
||||
}
|
||||
|
||||
WiFiClass32 WiFi32;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define ENC_TYPE_TKIP WIFI_AUTH_WPA_WPA2_PSK
|
||||
#define ENC_TYPE_AUTO WIFI_AUTH_MAX + 1
|
||||
|
||||
#define WIFI_NONE_SLEEP 0
|
||||
#define WIFI_LIGHT_SLEEP 1
|
||||
#define WIFI_MODEM_SLEEP 2
|
||||
|
||||
|
|
|
@ -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]
|
||||
framework = arduino
|
||||
board = esp01_1m
|
||||
board_build.filesystem = littlefs
|
||||
custom_unpack_dir = unpacked_littlefs
|
||||
board_build.flash_mode = dout
|
||||
board_build.ldscript = eagle.flash.1m.ld
|
||||
|
||||
|
@ -76,7 +78,8 @@ build_flags = ${core.build_flags}
|
|||
|
||||
board_build.f_cpu = 80000000L
|
||||
board_build.f_flash = 40000000L
|
||||
monitor_speed = 115200
|
||||
monitor_speed = 74880
|
||||
monitor_port = COM5
|
||||
upload_speed = 115200
|
||||
; *** Upload Serial reset method for Wemos and NodeMCU
|
||||
upload_resetmethod = nodemcu
|
||||
|
@ -98,6 +101,7 @@ extra_scripts = pio-tools/strip-floats.py
|
|||
pio-tools/name-firmware.py
|
||||
pio-tools/gzip-firmware.py
|
||||
pio-tools/override_copy.py
|
||||
pio-tools/download_fs.py
|
||||
|
||||
[esp_defaults]
|
||||
; *** remove undesired all warnings
|
||||
|
|
|
@ -48,6 +48,19 @@ build_flags = ${core.build_flags}
|
|||
; -DDEBUG_TASMOTA_DRIVER
|
||||
; -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
|
||||
;board_build.f_cpu = 160000000L
|
||||
|
||||
|
@ -103,39 +116,27 @@ build_flags = ${esp82xx_defaults.build_flags}
|
|||
-DWAVEFORM_LOCKED_PWM
|
||||
-Wno-switch-unreachable
|
||||
|
||||
|
||||
[common32]
|
||||
platform = ${core32.platform}
|
||||
platform_packages = ${core32.platform_packages}
|
||||
build_unflags = ${core32.build_unflags}
|
||||
build_flags = ${core32.build_flags}
|
||||
board = esp32dev
|
||||
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}
|
||||
upload_port = COM4
|
||||
lib_extra_dirs = ${library.lib_extra_dirs}
|
||||
; *** ESP32 lib. ALWAYS needed for ESP32 !!!
|
||||
lib/libesp32
|
||||
|
||||
[core32]
|
||||
; Activate Stage Core32 by removing ";" in next 3 lines, if you want to override the standard core32
|
||||
;platform_packages = ${core32_stage.platform_packages}
|
||||
;build_unflags = ${core32_stage.build_unflags}
|
||||
;build_flags = ${core32_stage.build_flags}
|
||||
|
||||
|
||||
[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
|
||||
build_unflags = ${esp32_defaults.build_unflags}
|
||||
build_flags = ${esp32_defaults.build_flags}
|
||||
-DESP32_STAGE=true
|
||||
;-DESP32_STAGE=true
|
||||
|
||||
[library]
|
||||
lib_ldf_mode = chain+
|
||||
|
@ -165,6 +166,7 @@ lib_extra_dirs =
|
|||
[env:tasmota32solo1]
|
||||
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
|
||||
platformio/tool-mklittlefs @ ~1.203.200522
|
||||
platformio/tool-esptoolpy @ ~1.30000.0
|
||||
build_unflags = ${esp32_defaults.build_unflags}
|
||||
build_flags = ${common32.build_flags}
|
||||
|
|
|
@ -47,6 +47,8 @@ platform_packages = ${core32.platform_packages}
|
|||
build_unflags = ${core32.build_unflags}
|
||||
build_flags = ${core32.build_flags}
|
||||
board = esp32dev
|
||||
board_build.filesystem = ${common.board_build.filesystem}
|
||||
custom_unpack_dir = ${common.custom_unpack_dir}
|
||||
board_build.ldscript = esp32_out.ld
|
||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
||||
|
|
|
@ -3,6 +3,7 @@ platform = ${common.platform}
|
|||
platform_packages = ${common.platform_packages}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
board_build.filesystem = ${common.board_build.filesystem}
|
||||
board_build.ldscript = ${common.board_build.ldscript}
|
||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
||||
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]
|
||||
build_flags = ${common.build_flags} -DFIRMWARE_ZBBRIDGE
|
||||
board_build.ldscript = eagle.flash.2m256.ld
|
||||
board_build.f_cpu = 160000000L
|
||||
lib_extra_dirs = lib/lib_ssl
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "my_user_config.h"
|
||||
#include "tasmota_configurations.h"
|
||||
|
||||
#if defined(ESP8266) && defined(USE_TLS)
|
||||
#include <stdint.h>
|
||||
#include <stdlib.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 */
|
||||
void stack_thunk_light_dump_stack()
|
||||
{
|
||||
uint32_t *pos = stack_thunk_light_top;
|
||||
while (pos < stack_thunk_light_ptr) {
|
||||
if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
|
||||
break;
|
||||
pos += 4;
|
||||
}
|
||||
ets_printf(">>>stack>>>\n");
|
||||
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]);
|
||||
pos += 4;
|
||||
}
|
||||
ets_printf("<<<stack<<<\n");
|
||||
}
|
||||
// void stack_thunk_light_dump_stack()
|
||||
// {
|
||||
// uint32_t *pos = stack_thunk_light_top;
|
||||
// while (pos < stack_thunk_light_ptr) {
|
||||
// if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint))
|
||||
// break;
|
||||
// pos += 4;
|
||||
// }
|
||||
// ets_printf(">>>stack>>>\n");
|
||||
// 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]);
|
||||
// pos += 4;
|
||||
// }
|
||||
// ets_printf("<<<stack<<<\n");
|
||||
// }
|
||||
|
||||
/* 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()
|
||||
{
|
||||
ets_printf("FATAL ERROR: BSSL stack overflow\n");
|
||||
// ets_printf("FATAL ERROR: BSSL stack overflow\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "my_user_config.h"
|
||||
#include "tasmota_configurations.h"
|
||||
#if defined(ESP8266) && defined(USE_TLS)
|
||||
#if defined(USE_TLS)
|
||||
|
||||
// #define DEBUG_TLS
|
||||
// #define DEBUG_ESP_SSL
|
||||
|
@ -47,7 +47,9 @@ extern "C" {
|
|||
#include "lwip/tcp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include <include/ClientContext.h>
|
||||
#ifdef ESP8266
|
||||
#include <include/ClientContext.h>
|
||||
#endif
|
||||
#include "c_types.h"
|
||||
|
||||
#include <core_version.h>
|
||||
|
@ -57,11 +59,15 @@ extern "C" {
|
|||
#include "coredecls.h"
|
||||
#define LOG_HEAP_SIZE(a) _Log_heap_size(a)
|
||||
void _Log_heap_size(const char *msg) {
|
||||
#ifdef ESP8266
|
||||
register uint32_t *sp asm("a1");
|
||||
int freestack = 4 * (sp - g_pcont->stack);
|
||||
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(),
|
||||
freestack, ESP.getFreeContStack());
|
||||
#elif defined(ESP32)
|
||||
Serial.printf("> Heap %s = %d\n", msg, uxTaskGetStackHighWaterMark(nullptr));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define LOG_HEAP_SIZE(a)
|
||||
|
@ -71,6 +77,7 @@ void _Log_heap_size(const char *msg) {
|
|||
extern uint32_t UtcTime(void);
|
||||
extern uint32_t CfgTime(void);
|
||||
|
||||
#ifdef ESP8266 // Stack thunk is not needed with ESP32
|
||||
// Stack thunked versions of calls
|
||||
// Initially in BearSSLHelpers.h
|
||||
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_buf min_br_ssl_engine_sendrec_buf
|
||||
|
||||
#endif // ESP8266
|
||||
|
||||
//#define DEBUG_ESP_SSL
|
||||
#ifdef DEBUG_ESP_SSL
|
||||
//#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
|
||||
WiFiClientSecure_light::WiFiClientSecure_light(int recv, int xmit) : WiFiClient() {
|
||||
_clear();
|
||||
LOG_HEAP_SIZE("StackThunk before");
|
||||
// LOG_HEAP_SIZE("StackThunk before");
|
||||
//stack_thunk_light_add_ref();
|
||||
LOG_HEAP_SIZE("StackThunk after");
|
||||
// LOG_HEAP_SIZE("StackThunk after");
|
||||
// now finish the setup
|
||||
setBufferSizes(recv, xmit); // reasonable minimum
|
||||
allocateBuffers();
|
||||
}
|
||||
|
||||
WiFiClientSecure_light::~WiFiClientSecure_light() {
|
||||
#ifdef ESP8266
|
||||
if (_client) {
|
||||
_client->unref();
|
||||
_client = nullptr;
|
||||
}
|
||||
#elif defined(ESP32)
|
||||
stop();
|
||||
#endif
|
||||
//_cipher_list = nullptr; // std::shared will free if last reference
|
||||
_freeSSL();
|
||||
}
|
||||
|
@ -258,6 +271,7 @@ void WiFiClientSecure_light::setBufferSizes(int recv, int xmit) {
|
|||
_iobuf_out_size = xmit;
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
bool WiFiClientSecure_light::stop(unsigned int maxWaitMs) {
|
||||
bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
|
||||
_freeSSL();
|
||||
|
@ -268,6 +282,17 @@ bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
|
|||
(void) _run_until(BR_SSL_SENDAPP);
|
||||
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) {
|
||||
DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
|
||||
|
@ -307,7 +332,11 @@ void WiFiClientSecure_light::_freeSSL() {
|
|||
}
|
||||
|
||||
bool WiFiClientSecure_light::_clientConnected() {
|
||||
#ifdef ESP8266
|
||||
return (_client && _client->state() == ESTABLISHED);
|
||||
#elif defined(ESP32)
|
||||
return WiFiClient::connected();
|
||||
#endif
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
|
||||
//LOG_HEAP_SIZE("_run_until 1");
|
||||
//LOG_HEAP_SIZE("_run_until 1");
|
||||
if (!ctx_present()) {
|
||||
DEBUG_BSSL("_run_until: Not connected\n");
|
||||
return -1;
|
||||
|
@ -506,9 +535,15 @@ int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) {
|
||||
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
|
||||
|
@ -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
|
||||
// ============================================================
|
||||
// allocate Thunk stack, move to alternate stack and initialize
|
||||
#ifdef ESP8266
|
||||
stack_thunk_light_add_ref();
|
||||
#endif // ESP8266
|
||||
LOG_HEAP_SIZE("Thunk allocated");
|
||||
DEBUG_BSSL("_connectSSL: start connection\n");
|
||||
_freeSSL();
|
||||
clearLastError();
|
||||
if (!stack_thunk_light_get_stack_bot()) break;
|
||||
#ifdef ESP8266
|
||||
if (!stack_thunk_light_get_stack_bot()) break;
|
||||
#endif // ESP8266
|
||||
|
||||
_ctx_present = true;
|
||||
_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
|
||||
LOG_HEAP_SIZE("_connectSSL.end");
|
||||
#ifdef ESP8266
|
||||
_max_thunkstack_use = stack_thunk_light_get_max_usage();
|
||||
stack_thunk_light_del_ref();
|
||||
//stack_thunk_light_repaint();
|
||||
LOG_HEAP_SIZE("_connectSSL.end, freeing StackThunk");
|
||||
#endif // ESP8266
|
||||
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
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
|
||||
setLastError(ERR_OOM);
|
||||
DEBUG_BSSL("_connectSSL: Out of memory\n");
|
||||
#ifdef ESP8266
|
||||
stack_thunk_light_del_ref();
|
||||
#endif
|
||||
#ifdef USE_MQTT_TLS_CA_CERT
|
||||
free(x509_minimal);
|
||||
#else
|
||||
|
|
|
@ -43,7 +43,11 @@ class WiFiClientSecure_light : public WiFiClient {
|
|||
|
||||
uint8_t connected() 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;
|
||||
#else
|
||||
size_t write_P(PGM_P buf, size_t size);
|
||||
#endif
|
||||
size_t write(const char *buf) {
|
||||
return write((const uint8_t*)buf, strlen(buf));
|
||||
}
|
||||
|
@ -55,11 +59,17 @@ class WiFiClientSecure_light : public WiFiClient {
|
|||
int available() override;
|
||||
int read() override;
|
||||
int peek() override;
|
||||
#ifdef ESP8266
|
||||
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||
bool flush(unsigned int maxWaitMs);
|
||||
bool stop(unsigned int maxWaitMs);
|
||||
void flush() override { (void)flush(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
|
||||
void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
|
||||
|
|
|
@ -680,7 +680,7 @@
|
|||
#define D_LOG_KNX "KNX: "
|
||||
#define D_LOG_LOG "LOG: " // Logging
|
||||
#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_OTHER "OTH: " // Other
|
||||
#define D_LOG_RESULT "RSL: " // Result
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
#define D_COMMAND "Befehl"
|
||||
#define D_CONNECTED "verbunden"
|
||||
#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_CT_POWER "CT Power"
|
||||
#define D_CURRENT "Strom" // As in Voltage and Current
|
||||
|
@ -143,8 +143,8 @@
|
|||
#define D_POWERUSAGE_REACTIVE "Blindleistung"
|
||||
#define D_PRESSURE "Luftdruck"
|
||||
#define D_PRESSUREATSEALEVEL "Luftdruck auf Meereshöhe"
|
||||
#define D_PROGRAM_FLASH_SIZE "Ges. Flash Speicher"
|
||||
#define D_PROGRAM_SIZE "Ben. Flash Speicher"
|
||||
#define D_PROGRAM_FLASH_SIZE "Flash nutzbar"
|
||||
#define D_PROGRAM_SIZE "Größe Programm"
|
||||
#define D_PROJECT "Projekt"
|
||||
#define D_RAIN "Regen"
|
||||
#define D_RANGE "Bereich"
|
||||
|
@ -333,7 +333,7 @@
|
|||
#define D_PROGRAM_VERSION "Tasmota Version"
|
||||
#define D_BUILD_DATE_AND_TIME "Build-Datum & -Uhrzeit"
|
||||
#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_MQTT_HOST "MQTT Host"
|
||||
#define D_MQTT_PORT "MQTT Port"
|
||||
|
@ -343,12 +343,12 @@
|
|||
#define D_MQTT_GROUP_TOPIC "MQTT Group Topic"
|
||||
#define D_MQTT_FULL_TOPIC "MQTT Full Topic"
|
||||
#define D_MQTT_NO_RETAIN "MQTT No Retain"
|
||||
#define D_MDNS_DISCOVERY "mDNS-Ermittlung"
|
||||
#define D_MDNS_ADVERTISE "mDNS-Bekanntmachung"
|
||||
#define D_MDNS_DISCOVERY "mDNS-Erkennung"
|
||||
#define D_MDNS_ADVERTISE "mDNS-Freigaben"
|
||||
#define D_ESP_CHIP_ID "ESP Chip ID"
|
||||
#define D_FLASH_CHIP_ID "Flash Chip ID"
|
||||
#define D_FLASH_CHIP_SIZE "Realer Flash Speicher"
|
||||
#define D_FREE_PROGRAM_SPACE "Verf. Flash Speicher"
|
||||
#define D_FLASH_CHIP_SIZE "Größe Flash-Chip"
|
||||
#define D_FREE_PROGRAM_SPACE "Flash frei"
|
||||
|
||||
#define D_UPGRADE_BY_WEBSERVER "Update über Web-Server"
|
||||
#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_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 ------------------------------
|
||||
//#define USE_TIMEPROP // Add support for the timeprop feature (+0k8 code)
|
||||
// -- PID and Timeprop ------------------------------ // Both together will add +12k1 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
|
||||
//#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
|
||||
// -- End of general directives ---------------------
|
||||
|
||||
|
|
|
@ -154,19 +154,20 @@ bool RtcRebootValid(void)
|
|||
* 0x000xxxxx - Unzipped binary code end
|
||||
* 0x000x1000 - First page used by Core OTA
|
||||
* ::::
|
||||
* 0x000F2FFF
|
||||
* 0x000F2FFF 0x000F5FFF 0x000F5FFF
|
||||
******************************************************************************
|
||||
* Next 32k is overwritten by OTA
|
||||
* 0x000F3000 - 4k Tasmota Quick Power Cycle counter (SETTINGS_LOCATION - CFG_ROTATES) - First four bytes only
|
||||
* 0x000F3FFF
|
||||
* 0x000F4000 - 4k First Tasmota rotating settings page
|
||||
* 0x000F3000 0x000F6000 0x000F6000 - 4k Tasmota Quick Power Cycle counter (SETTINGS_LOCATION - CFG_ROTATES) - First four bytes only
|
||||
* 0x000F3FFF 0x000F6FFF 0x000F6FFF
|
||||
* 0x000F4000 0x000F7000 0x000F7000 - 4k First Tasmota rotating settings page
|
||||
* ::::
|
||||
* 0x000FA000 - 4k Last Tasmota rotating settings page = Last page used by Core OTA (SETTINGS_LOCATION)
|
||||
* 0x000FAFFF
|
||||
* 0x000FA000 0x000FD000 0x000FD000 - 4k Last Tasmota rotating settings page = Last page used by Core OTA (SETTINGS_LOCATION)
|
||||
* 0x000FAFFF 0x000FDFFF 0x000FDFFF
|
||||
******************************************************************************
|
||||
* 0x000FB000 0x000FB000 - 15k9 Not used
|
||||
* 0x000FE000 0x000FE000 - 3k9 Not used
|
||||
* 0x000FEFF0 0x000FEFF0 - 4k1 Empty
|
||||
* 0x000FFFFF 0x000FFFFF
|
||||
*
|
||||
* 0x000FB000 0x00100000 0x00100000 - 0k, 980k or 2980k Core FS start (LittleFS)
|
||||
* 0x000FB000 0x001FA000 0x003FA000 - 0k, 980k or 2980k Core FS end (LittleFS)
|
||||
* 0x001FAFFF 0x003FAFFF
|
||||
|
@ -189,7 +190,8 @@ extern "C" {
|
|||
#ifdef ESP8266
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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_crc32 = 0;
|
||||
uint8_t *settings_buffer = nullptr;
|
||||
|
||||
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();
|
||||
|
||||
#ifdef ESP8266
|
||||
#ifdef USE_UFILESYS
|
||||
TfsSaveFile(TASM_FILE_SETTINGS, (const uint8_t*)&Settings, sizeof(Settings));
|
||||
#endif // USE_UFILESYS
|
||||
if (ESP.flashEraseSector(settings_location)) {
|
||||
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
||||
}
|
||||
|
@ -559,39 +566,66 @@ void SettingsSave(uint8_t rotate)
|
|||
|
||||
void SettingsLoad(void) {
|
||||
#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
|
||||
settings_location = 0;
|
||||
uint32_t save_flag = 0;
|
||||
uint32_t flash_location = FLASH_EEPROM_START;
|
||||
for (uint32_t i = 0; i < CFG_ROTATES; i++) { // Read all config pages in search of valid and latest
|
||||
if (1 == i) { flash_location = SETTINGS_LOCATION; }
|
||||
ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings));
|
||||
uint32_t max_slots = CFG_ROTATES +1;
|
||||
uint32_t flash_location;
|
||||
uint32_t slot = 1;
|
||||
#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.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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
flash_location--;
|
||||
slot++;
|
||||
delay(1);
|
||||
}
|
||||
if (settings_location > 0) {
|
||||
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);
|
||||
#ifdef USE_UFILESYS
|
||||
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
|
||||
#ifdef ESP32
|
||||
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);
|
||||
#endif // ESP32
|
||||
|
||||
#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
|
||||
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();
|
||||
#endif // FIRMWARE_MINIMAL
|
||||
|
@ -604,25 +638,6 @@ uint32_t CfgTime(void) {
|
|||
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
|
||||
void SettingsErase(uint8_t type)
|
||||
{
|
||||
|
@ -635,54 +650,52 @@ void SettingsErase(uint8_t type)
|
|||
|
||||
The default erase function is EspTool (EsptoolErase)
|
||||
|
||||
0 = Erase from program end until end of flash as seen by SDK
|
||||
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)
|
||||
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
|
||||
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)
|
||||
4 = Erase SDK parameter area used for wifi calibration (0x0FCxxx - 0x0FCFFF)
|
||||
*/
|
||||
|
||||
#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 _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
|
||||
_sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4; // SDK parameter area
|
||||
}
|
||||
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)
|
||||
_sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4;
|
||||
}
|
||||
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) {
|
||||
_sectorStart = (ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE) -4; // SDK phy area and Core calibration sector (0xxFC000)
|
||||
_sectorEnd = _sectorStart +1; // SDK end of phy area and Core calibration sector (0xxFCFFF)
|
||||
}
|
||||
#ifdef USE_UFILESYS
|
||||
TfsDeleteFile(TASM_FILE_SETTINGS); // Not needed as it is recreated by set defaults before restart
|
||||
#endif
|
||||
*/
|
||||
else {
|
||||
return;
|
||||
EsptoolErase(_sectorStart, FLASH_FS_START);
|
||||
_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);
|
||||
|
||||
// EspErase(_sectorStart, _sectorEnd); // Arduino core and SDK - erases flash as seen by SDK
|
||||
EsptoolErase(_sectorStart, _sectorEnd); // Esptool - erases flash completely
|
||||
EsptoolErase(_sectorStart, _sectorEnd); // Esptool - erases flash completely
|
||||
#endif // FIRMWARE_MINIMAL
|
||||
}
|
||||
#endif // ESP8266
|
||||
|
||||
void SettingsSdkErase(void)
|
||||
{
|
||||
WiFi.disconnect(false); // Delete SDK wifi config
|
||||
WiFi.disconnect(false); // Delete SDK wifi config
|
||||
SettingsErase(1);
|
||||
delay(1000);
|
||||
}
|
||||
|
|
|
@ -727,12 +727,12 @@ void CmndRestart(void)
|
|||
switch (XdrvMailbox.payload) {
|
||||
case 1:
|
||||
TasmotaGlobal.restart_flag = 2;
|
||||
ResponseCmndChar(D_JSON_RESTARTING);
|
||||
ResponseCmndChar(PSTR(D_JSON_RESTARTING));
|
||||
break;
|
||||
case 2:
|
||||
TasmotaGlobal.restart_flag = 2;
|
||||
TasmotaGlobal.restart_halt = true;
|
||||
ResponseCmndChar(D_JSON_HALTING);
|
||||
ResponseCmndChar(PSTR(D_JSON_HALTING));
|
||||
break;
|
||||
case -1:
|
||||
CmndCrash(); // force a crash
|
||||
|
@ -967,8 +967,9 @@ void CmndSetoption(void)
|
|||
bitWrite(Settings.flag5.data, pindex, XdrvMailbox.payload);
|
||||
switch (pindex) {
|
||||
case 1: // SetOption115 - Enable ESP32 MI32
|
||||
Settings.flag3.sleep_normal = 1; // SetOption60 - Enable normal sleep instead of dynamic sleep
|
||||
TasmotaGlobal.restart_flag = 2;
|
||||
if (0 == XdrvMailbox.payload) {
|
||||
TasmotaGlobal.restart_flag = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1208,7 +1209,7 @@ void CmndGpio(void)
|
|||
if (jsflg2) {
|
||||
ResponseClear();
|
||||
} 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) {
|
||||
// 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
|
||||
// qpc - Tasmota Quick Power Cycle state
|
||||
// main - Tasmota Settings data
|
||||
int32_t r1, r2, r3;
|
||||
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.
|
||||
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 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 = NvmErase("cal_data");
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " PHY data (%d)"), r1);
|
||||
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)
|
||||
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
|
||||
r1 = NvmErase("qpc");
|
||||
|
|
|
@ -95,6 +95,8 @@ bool EsptoolEraseSector(uint32_t 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 remaining_erase_sector = end_sector - start_sector;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ void StartMdns(void) {
|
|||
// mdns_delayed_start--;
|
||||
// } else {
|
||||
// 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);
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
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;
|
||||
tv.tv_sec = Rtc.local_time;
|
||||
tv.tv_usec = 0;
|
||||
settimeofday(&tv, nullptr);
|
||||
}
|
||||
#endif // ESP32
|
||||
|
||||
}
|
||||
|
||||
RtcTime.year += 1970;
|
||||
|
|
|
@ -886,6 +886,15 @@ void PerformEverySecond(void)
|
|||
ESP_getSketchSize(); // Init sketchsize as it can take up to 2 seconds
|
||||
}
|
||||
#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
|
||||
// }
|
||||
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();
|
||||
// Restore current SSIDs and Passwords
|
||||
|
@ -1169,7 +1178,7 @@ void Every250mSeconds(void)
|
|||
}
|
||||
TasmotaGlobal.restart_flag--;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1616,8 +1625,8 @@ void GpioInit(void)
|
|||
if (!TasmotaGlobal.soft_spi_enabled) {
|
||||
bool valid_cs = (ValidSpiPinUsed(GPIO_SPI_CS) ||
|
||||
ValidSpiPinUsed(GPIO_RC522_CS) ||
|
||||
ValidSpiPinUsed(GPIO_NRF24_CS) ||
|
||||
ValidSpiPinUsed(GPIO_ILI9341_CS) ||
|
||||
(ValidSpiPinUsed(GPIO_NRF24_CS) && ValidSpiPinUsed(GPIO_NRF24_DC)) ||
|
||||
(ValidSpiPinUsed(GPIO_ILI9341_CS) && ValidSpiPinUsed(GPIO_ILI9341_DC)) ||
|
||||
ValidSpiPinUsed(GPIO_EPAPER29_CS) ||
|
||||
ValidSpiPinUsed(GPIO_EPAPER42_CS) ||
|
||||
ValidSpiPinUsed(GPIO_ILI9488_CS) ||
|
||||
|
@ -1625,17 +1634,11 @@ void GpioInit(void)
|
|||
ValidSpiPinUsed(GPIO_RA8876_CS) ||
|
||||
ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too
|
||||
ValidSpiPinUsed(GPIO_ST7789_CS) ||
|
||||
ValidSpiPinUsed(GPIO_SSD1331_CS) ||
|
||||
(ValidSpiPinUsed(GPIO_SSD1331_CS) && ValidSpiPinUsed(GPIO_SSD1331_DC)) ||
|
||||
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
|
||||
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) {
|
||||
TasmotaGlobal.my_module.io[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
|
||||
|
||||
bool udp_connected = false;
|
||||
bool udp_response_mutex = false; // M-Search response mutex to control re-entry
|
||||
|
||||
#ifdef ESP8266
|
||||
#ifndef UDP_MAX_PACKETS
|
||||
|
@ -89,14 +88,12 @@ bool UdpConnect(void)
|
|||
if (UdpCtx.listen(&addr, 1900)) { // port 1900
|
||||
// OK
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
||||
udp_response_mutex = false;
|
||||
udp_connected = true;
|
||||
}
|
||||
#endif // ESP8266
|
||||
#ifdef ESP32
|
||||
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED));
|
||||
udp_response_mutex = false;
|
||||
udp_connected = true;
|
||||
#endif // ESP32
|
||||
}
|
||||
|
@ -123,28 +120,29 @@ void PollUdp(void)
|
|||
packet->buf[packet->len] = 0; // add NULL at the end of the packet
|
||||
char * packet_buffer = (char*) &packet->buf;
|
||||
int32_t len = packet->len;
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
|
||||
#endif // ESP8266
|
||||
#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
|
||||
|
||||
int32_t len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1);
|
||||
packet_buffer[len] = 0;
|
||||
PortUdp.flush();
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d/%d)"), len, pack_len);
|
||||
#endif // ESP32
|
||||
AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len);
|
||||
|
||||
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
|
||||
|
||||
// Simple Service Discovery Protocol (SSDP)
|
||||
if (Settings.flag2.emulation) {
|
||||
#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
|
||||
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
|
||||
if (0 == udp_last_received) {
|
||||
udp_last_received = millis();
|
||||
udp_response_mutex = true;
|
||||
|
||||
#ifdef ESP8266
|
||||
udp_remote_ip = packet->srcaddr;
|
||||
udp_remote_port = packet->srcport;
|
||||
|
@ -159,35 +157,34 @@ void PollUdp(void)
|
|||
LowerCase(packet_buffer, packet_buffer);
|
||||
RemoveSpace(packet_buffer);
|
||||
|
||||
bool udp_proccessed = false; // make sure we process the packet only once
|
||||
#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
|
||||
WemoRespondToMSearch(1);
|
||||
return;
|
||||
udp_proccessed = true;
|
||||
}
|
||||
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, SSDP_ALL) != nullptr)) {
|
||||
WemoRespondToMSearch(2);
|
||||
return;
|
||||
udp_proccessed = true;
|
||||
}
|
||||
}
|
||||
#endif // USE_EMULATION_WEMO
|
||||
|
||||
#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) ||
|
||||
(strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) ||
|
||||
(strstr_P(packet_buffer, SSDP_ALL) != nullptr)) {
|
||||
HueRespondToMSearch();
|
||||
return;
|
||||
udp_proccessed = true;
|
||||
}
|
||||
}
|
||||
#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
|
||||
/*
|
||||
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
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -735,6 +748,7 @@ uint32_t WifiGetNtp(void) {
|
|||
char* ntp_server;
|
||||
bool resolved_ip = false;
|
||||
for (uint32_t i = 0; i <= MAX_NTP_SERVERS; i++) {
|
||||
if (ntp_server_id > 2) { ntp_server_id = 0; }
|
||||
if (i < MAX_NTP_SERVERS) {
|
||||
ntp_server = SettingsText(SET_NTPSERVER1 + ntp_server_id);
|
||||
} else {
|
||||
|
@ -747,7 +761,6 @@ uint32_t WifiGetNtp(void) {
|
|||
if (resolved_ip) { break; }
|
||||
}
|
||||
ntp_server_id++;
|
||||
if (ntp_server_id > 2) { ntp_server_id = 0; }
|
||||
}
|
||||
if (!resolved_ip) {
|
||||
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: No server found"));
|
||||
|
@ -785,8 +798,7 @@ uint32_t WifiGetNtp(void) {
|
|||
packet_buffer[15] = 52;
|
||||
|
||||
if (udp.beginPacket(time_server_ip, 123) == 0) { // NTP requests are to port 123
|
||||
ntp_server_id++;
|
||||
if (ntp_server_id > 2) { ntp_server_id = 0; } // Next server next time
|
||||
ntp_server_id++; // Next server next time
|
||||
udp.stop();
|
||||
return 0;
|
||||
}
|
||||
|
@ -806,6 +818,7 @@ uint32_t WifiGetNtp(void) {
|
|||
// Leap-Indicator: unknown (clock unsynchronized)
|
||||
// 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());
|
||||
ntp_server_id++; // Next server next time
|
||||
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[43];
|
||||
if (0 == secs_since_1900) { // No time stamp received
|
||||
ntp_server_id++; // Next server next time
|
||||
return 0;
|
||||
}
|
||||
return secs_since_1900 - 2208988800UL;
|
||||
|
@ -825,6 +839,7 @@ uint32_t WifiGetNtp(void) {
|
|||
// Timeout.
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NTP: No reply"));
|
||||
udp.stop();
|
||||
ntp_server_id++; // Next server next time
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ struct {
|
|||
bool skip_light_fade; // Temporarily skip light fading
|
||||
bool restart_halt; // Do not restart but stay in wait loop
|
||||
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)
|
||||
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"
|
||||
#endif
|
||||
|
||||
#define TASM_FILE_SETTINGS "/.settings"
|
||||
#define TASM_FILE_ZIGBEE "/zb"
|
||||
#define TASM_FILE_SETTINGS "/.settings" // Settings binary blob
|
||||
#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
|
||||
#define MQTT_MAX_PACKET_SIZE 1200 // Bytes
|
||||
|
|
|
@ -475,14 +475,14 @@ void StartWebserver(int type, IPAddress ipweb)
|
|||
String ipv6_addr = WifiGetIPv6();
|
||||
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 "),
|
||||
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 {
|
||||
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
|
||||
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
|
||||
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);
|
||||
WSContentSend_P(PSTR("<h4>%s%s (%s%s%s)</h4>"), // tasmota.local (192.168.2.12, 192.168.4.1)
|
||||
NetworkHostname(),
|
||||
(Mdns.begun) ? ".local" : "",
|
||||
(Mdns.begun) ? PSTR(".local") : "",
|
||||
(lip) ? WiFi.localIP().toString().c_str() : "",
|
||||
(lip && sip) ? ", " : "",
|
||||
(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;
|
||||
#ifdef USE_SONOFF_IFAN
|
||||
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();
|
||||
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 {
|
||||
#endif // USE_SONOFF_IFAN
|
||||
for (uint32_t idx = 1; idx <= TasmotaGlobal.devices_present; idx++) {
|
||||
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
|
||||
}
|
||||
|
@ -1438,7 +1438,7 @@ void HandleTemplateConfiguration(void)
|
|||
for (uint32_t i = 0; i < MAX_GPIO_PIN; 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>"),
|
||||
((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);
|
||||
}
|
||||
}
|
||||
|
@ -1824,7 +1824,7 @@ void HandleLoggingConfiguration(void)
|
|||
idx);
|
||||
for (uint32_t i = LOG_LEVEL_NONE; i <= LOG_LEVEL_DEBUG_MORE; i++) {
|
||||
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));
|
||||
}
|
||||
WSContentSend_P(PSTR("</select></p>"));
|
||||
|
@ -1880,8 +1880,8 @@ void HandleOtherConfiguration(void)
|
|||
TemplateJson();
|
||||
char stemp[strlen(TasmotaGlobal.mqtt_data) +1];
|
||||
strlcpy(stemp, TasmotaGlobal.mqtt_data, sizeof(stemp)); // Get JSON template
|
||||
WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "",
|
||||
(Settings.flag.mqtt_enabled) ? " checked" : "", // SetOption3 - Enable MQTT
|
||||
WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? PSTR(" checked disabled") : "",
|
||||
(Settings.flag.mqtt_enabled) ? PSTR(" checked") : "", // SetOption3 - Enable MQTT
|
||||
SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME));
|
||||
|
||||
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) {
|
||||
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 == Settings.flag2.emulation) ? " checked" : "",
|
||||
(i == Settings.flag2.emulation) ? PSTR(" checked") : "",
|
||||
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>"));
|
||||
|
@ -2086,7 +2086,7 @@ void HandleInformation(void)
|
|||
#ifdef ESP32
|
||||
#ifdef USE_ETHERNET
|
||||
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_IP_ADDRESS " (eth)}2%s"), EthernetLocalIP().toString().c_str());
|
||||
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
|
||||
|
@ -2096,7 +2096,7 @@ void HandleInformation(void)
|
|||
if (Settings.flag4.network_wifi) {
|
||||
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_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
|
||||
String ipv6_addr = WifiGetIPv6();
|
||||
if (ipv6_addr != "") {
|
||||
|
@ -2169,15 +2169,15 @@ void HandleInformation(void)
|
|||
#ifdef ESP8266
|
||||
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId());
|
||||
#endif
|
||||
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP_getSketchSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%dkB"), freeMem / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%d kB"), ESP.getFlashChipRealSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%d kB"), ESP.getFlashChipSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%d kB"), ESP_getSketchSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%d kB"), ESP.getFreeSketchSpace() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%d kB"), freeMem / 1024);
|
||||
#ifdef ESP32
|
||||
if (psramFound()) {
|
||||
WSContentSend_P(PSTR("}1" D_PSR_MAX_MEMORY "}2%dkB"), ESP.getPsramSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PSR_FREE_MEMORY "}2%dkB"), ESP.getFreePsram() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PSR_MAX_MEMORY "}2%d kB"), ESP.getPsramSize() / 1024);
|
||||
WSContentSend_P(PSTR("}1" D_PSR_FREE_MEMORY "}2%d kB"), ESP.getFreePsram() / 1024);
|
||||
}
|
||||
#endif
|
||||
WSContentSend_P(PSTR("</td></tr></table>"));
|
||||
|
@ -2522,7 +2522,7 @@ void HandleUploadLoop(void) {
|
|||
return;
|
||||
}
|
||||
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())) {
|
||||
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.
|
||||
Webserver->client().stop(); // Stop is needed because we sent no content length
|
||||
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)) {
|
||||
#ifdef USE_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"),
|
||||
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()) {
|
||||
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),
|
||||
Settings.mqtt_port,
|
||||
#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
|
||||
Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, SettingsText(SET_MQTT_CLIENT));
|
||||
WSContentSend_P(HTTP_FORM_MQTT2,
|
||||
|
|
|
@ -537,6 +537,7 @@ void EnergyEverySecond(void)
|
|||
}
|
||||
if (!data_valid) {
|
||||
Energy.start_energy = 0;
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("NRG: Energy reset by " STR(ENERGY_WATCHDOG) " seconds invalid data"));
|
||||
|
||||
XnrgCall(FUNC_ENERGY_RESET);
|
||||
}
|
||||
|
|
|
@ -305,7 +305,7 @@ void PrepShowTimer(uint32_t index)
|
|||
char days[8] = { 0 };
|
||||
for (uint32_t i = 0; i < 7; 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];
|
||||
|
@ -857,7 +857,7 @@ void HandleTimerConfiguration(void)
|
|||
WSContentSend_P(HTTP_TIMER_SCRIPT5, MAX_TIMERS, TasmotaGlobal.devices_present);
|
||||
WSContentSend_P(HTTP_TIMER_SCRIPT6, TasmotaGlobal.devices_present);
|
||||
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++) {
|
||||
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=='#') {
|
||||
// check for parameter
|
||||
ctype += tlen;
|
||||
if (*ctype=='(' && *(lp+tlen)=='(') {
|
||||
float fparam;
|
||||
numeric = 1;
|
||||
glob_script_mem.glob_error = 0;
|
||||
GetNumericArgument((char*)ctype, OPER_EQU, &fparam, 0);
|
||||
if (glob_script_mem.glob_error==1) {
|
||||
// was string, not number
|
||||
numeric = 0;
|
||||
// get the string
|
||||
GetStringArgument((char*)ctype + 1, OPER_EQU, cmpstr, 0);
|
||||
}
|
||||
lp += tlen;
|
||||
if (*lp=='(') {
|
||||
// fetch destination
|
||||
lp++;
|
||||
lp = isvar(lp, &vtype, &ind, 0, 0, 0);
|
||||
if (vtype!=VAR_NV) {
|
||||
// found variable as result
|
||||
uint8_t index = glob_script_mem.type[ind.index].index;
|
||||
if ((vtype&STYPE)==0) {
|
||||
// numeric result
|
||||
dfvar = &glob_script_mem.fvars[index];
|
||||
if (numeric) {
|
||||
*dfvar = fparam;
|
||||
} else {
|
||||
// mismatch
|
||||
*dfvar = CharToFloat(cmpstr);
|
||||
}
|
||||
} else {
|
||||
// string result
|
||||
sindex = index;
|
||||
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));
|
||||
}
|
||||
char nxttok = '(';
|
||||
char *argptr = ctype+tlen;
|
||||
|
||||
lp += tlen;
|
||||
do {
|
||||
if (*ctype==nxttok && *lp==nxttok) {
|
||||
float fparam;
|
||||
numeric = 1;
|
||||
glob_script_mem.glob_error = 0;
|
||||
argptr = GetNumericArgument((char*)ctype + 1, OPER_EQU, &fparam, 0);
|
||||
if (glob_script_mem.glob_error==1) {
|
||||
// was string, not number
|
||||
numeric = 0;
|
||||
// get the string
|
||||
argptr = GetStringArgument((char*)ctype + 1, OPER_EQU, cmpstr, 0);
|
||||
}
|
||||
if (*lp==nxttok) {
|
||||
// fetch destination
|
||||
lp++;
|
||||
lp = isvar(lp, &vtype, &ind, 0, 0, 0);
|
||||
if (vtype!=VAR_NV) {
|
||||
// found variable as result
|
||||
uint8_t index = glob_script_mem.type[ind.index].index;
|
||||
if ((vtype&STYPE)==0) {
|
||||
// numeric result
|
||||
dfvar = &glob_script_mem.fvars[index];
|
||||
if (numeric) {
|
||||
*dfvar = fparam;
|
||||
} else {
|
||||
// mismatch
|
||||
*dfvar = CharToFloat(cmpstr);
|
||||
}
|
||||
} else {
|
||||
// string result
|
||||
sindex = index;
|
||||
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 {
|
||||
lp += tlen;
|
||||
if (*ctype=='(' || (*lp!=SCRIPT_EOL && *lp!='?')) {
|
||||
// revert
|
||||
section = 0;
|
||||
}
|
||||
}
|
||||
nxttok = ' ';
|
||||
ctype = argptr;
|
||||
} while (*lp==' ' && (section == 1) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4973,9 +4979,9 @@ void HandleScriptConfiguration(void) {
|
|||
#ifdef xSCRIPT_STRIP_COMMENTS
|
||||
uint16_t ssize = glob_script_mem.script_size;
|
||||
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
|
||||
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
|
||||
|
||||
// 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
|
||||
"\"rl\":[%s],\"swc\":[%s],\"swn\":[%s],\"btn\":[%s]," // Inputs / Outputs
|
||||
"\"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
|
||||
|
||||
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,
|
||||
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,
|
||||
light_controller.isCTRGBLinked(), Light.subtype, stemp6);
|
||||
Settings.flag5.fade_fixed_duration, light_controller.isCTRGBLinked(), Light.subtype, stemp6);
|
||||
}
|
||||
MqttPublish(stopic, true);
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ String HueBridgeId(void)
|
|||
String temp = WiFi.macAddress();
|
||||
temp.replace(":", "");
|
||||
String bridgeid = temp.substring(0, 6);
|
||||
bridgeid += "FFFE";
|
||||
bridgeid += F("FFFE");
|
||||
bridgeid += temp.substring(6);
|
||||
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
|
||||
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);
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
udp_response_mutex = false;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
|
|
@ -422,8 +422,6 @@ void WemoRespondToMSearch(int echo_type) {
|
|||
for (uint32_t i = 0; i < numOfWemoSwitch; i++) {
|
||||
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) {
|
||||
char key[8];
|
||||
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 {
|
||||
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());
|
||||
arr_data.addStr(key);
|
||||
|
|
|
@ -1903,7 +1903,7 @@ void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class
|
|||
y = buf2.get16(2);
|
||||
x = buf2.get16(4);
|
||||
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);
|
||||
// calculate angles
|
||||
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_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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -785,7 +785,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
|||
ZI_WAIT_UNTIL(5000, ZBR_RSTACK) // wait for RSTACK message
|
||||
|
||||
// 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
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
|
||||
|
|
|
@ -171,7 +171,7 @@ void Z_Mapper::dumpInternals(void) const {
|
|||
char hex[8];
|
||||
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);
|
||||
}
|
||||
WSContentSend_P(PSTR("],"));
|
||||
|
|
|
@ -2081,7 +2081,7 @@ void ZigbeeShow(bool json)
|
|||
if (zigbee.permit_end_time) {
|
||||
// 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
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ void HandlePcf8574(void)
|
|||
|
||||
WSContentStart_P(D_CONFIGURE_PCF8574);
|
||||
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);
|
||||
for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) {
|
||||
for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574
|
||||
|
@ -177,8 +177,8 @@ void HandlePcf8574(void)
|
|||
idx +1, idx2,
|
||||
idx2 + 8*idx,
|
||||
idx2 + 8*idx,
|
||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? " selected " : " ",
|
||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? " selected " : " "
|
||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? PSTR(" 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
|
||||
else{_buf[0]=(float)_line;}
|
||||
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;
|
||||
}
|
||||
WebGetArg("up", tmp, sizeof(tmp)); // update POI to browser
|
||||
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;
|
||||
}
|
||||
else if (strlen(tmp)>2) { // receive updated POI from browser
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#ifdef USE_TIMEPROP
|
||||
#ifndef FIRMWARE_MINIMAL
|
||||
/*********************************************************************************************\
|
||||
* Code to drive one or more relays in a time proportioned manner give a
|
||||
* required power value.
|
||||
|
@ -79,7 +80,23 @@
|
|||
#define TIMEPROP_RELAYS 1, 2 // which relay to control 1:8
|
||||
|
||||
* 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
|
||||
#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
|
||||
#endif
|
||||
|
||||
#include "Timeprop.h"
|
||||
|
||||
struct {
|
||||
Timeprop timeprops[TIMEPROP_NUM_OUTPUTS];
|
||||
int relay_nos[TIMEPROP_NUM_OUTPUTS] = {TIMEPROP_RELAYS};
|
||||
|
@ -162,7 +177,51 @@ void TimepropXdrvPower(void) {
|
|||
/* char *data; */
|
||||
/* } 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
|
||||
|
@ -180,6 +239,9 @@ bool Xdrv48(byte function) {
|
|||
case FUNC_EVERY_SECOND:
|
||||
TimepropEverySecond();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = TimepropCommand();
|
||||
break;
|
||||
case FUNC_SET_POWER:
|
||||
TimepropXdrvPower();
|
||||
break;
|
||||
|
@ -187,4 +249,5 @@ bool Xdrv48(byte function) {
|
|||
return result;
|
||||
}
|
||||
|
||||
#endif // FIRMWARE_MINIMAL
|
||||
#endif // USE_TIMEPROP
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#ifdef USE_PID
|
||||
#ifndef FIRMWARE_MINIMAL
|
||||
/*********************************************************************************************\
|
||||
* Uses the library https://github.com/colinl/process-control.git from Github
|
||||
* 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
|
||||
// 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
|
||||
* 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
|
||||
|
@ -271,26 +267,27 @@ void CmndSetPv(void) {
|
|||
// this runs it at the next second
|
||||
Pid.run_pid_now = true;
|
||||
}
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetSp(void) {
|
||||
Pid.pid.setSp(atof(XdrvMailbox.data));
|
||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetPb(void) {
|
||||
Pid.pid.setPb(atof(XdrvMailbox.data));
|
||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetTi(void) {
|
||||
Pid.pid.setTi(atof(XdrvMailbox.data));
|
||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetTd(void) {
|
||||
Pid.pid.setTd(atof(XdrvMailbox.data));
|
||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetInitialInt(void) {
|
||||
|
@ -300,7 +297,7 @@ void CmndSetInitialInt(void) {
|
|||
|
||||
void CmndSetDSmooth(void) {
|
||||
Pid.pid.setDSmooth(atof(XdrvMailbox.data));
|
||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetAuto(void) {
|
||||
|
@ -310,7 +307,7 @@ void CmndSetAuto(void) {
|
|||
|
||||
void CmndSetManualPower(void) {
|
||||
Pid.pid.setManualPower(atof(XdrvMailbox.data));
|
||||
ResponseCmndNumber(atof(XdrvMailbox.data));
|
||||
ResponseCmndFloat(atof(XdrvMailbox.data), 1);
|
||||
}
|
||||
|
||||
void CmndSetMaxInterval(void) {
|
||||
|
@ -391,14 +388,14 @@ void PIDShowValues(void) {
|
|||
|
||||
void PIDRun(void) {
|
||||
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
|
||||
// `%topic%/PID {"power":"0.000"}`
|
||||
char str_buf[FLOATSZ];
|
||||
dtostrfd(power, 3, str_buf);
|
||||
snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s\":\"%s\"}"), "power", str_buf);
|
||||
MqttPublishPrefixTopic_P(TELE, "PID", false);
|
||||
#endif // PID_BACKWARD_COMPATIBLE
|
||||
#endif // PID_DONT_USE_PID_TOPIC
|
||||
|
||||
#if defined PID_SHUTTER
|
||||
// send output as a position from 0-100 to defined shutter
|
||||
|
@ -443,4 +440,5 @@ bool Xdrv49(byte function) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
#endif //FIRMWARE_MINIMAL
|
||||
#endif // USE_PID
|
||||
|
|
|
@ -72,25 +72,28 @@ ufsfree free size in kB
|
|||
#include "FS.h"
|
||||
#endif // ESP32
|
||||
|
||||
// global file system pointer
|
||||
// Global file system pointer
|
||||
FS *ufsp;
|
||||
// flash file system pointer on esp32
|
||||
// Flash file system pointer
|
||||
FS *ffsp;
|
||||
// local pointer for file managment
|
||||
// Local pointer for file managment
|
||||
FS *dfsp;
|
||||
|
||||
char ufs_path[48];
|
||||
File ufs_upload_file;
|
||||
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 ffs_type;
|
||||
bool download_busy;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
// init flash file system
|
||||
// Init flash file system
|
||||
void UfsInitOnce(void) {
|
||||
ufs_type = 0;
|
||||
ffsp = 0;
|
||||
|
@ -130,21 +133,13 @@ void UfsInitOnce(void) {
|
|||
void UfsInit(void) {
|
||||
UfsInitOnce();
|
||||
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
|
||||
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) {
|
||||
#endif // ESP32
|
||||
int8_t cs = SDCARD_CS_PIN;
|
||||
if (PinUsed(GPIO_SDCARD_CS)) {
|
||||
cs = Pin(GPIO_SDCARD_CS);
|
||||
|
@ -172,10 +167,10 @@ void UfsCheckSDCardInit(void) {
|
|||
// make sd card the global filesystem
|
||||
#ifdef ESP8266
|
||||
// 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
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
@ -274,38 +269,12 @@ uint8_t UfsReject(char *name) {
|
|||
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
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool TfsFileExists(const char *fname){
|
||||
if (!ufs_type) { return false; }
|
||||
if (!ffs_type) { return false; }
|
||||
|
||||
bool yes = ffsp->exists(fname);
|
||||
if (!yes) {
|
||||
|
@ -315,7 +284,7 @@ bool TfsFileExists(const char *fname){
|
|||
}
|
||||
|
||||
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");
|
||||
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) {
|
||||
if (!ufs_type) { return false; }
|
||||
if (!ffs_type) { return false; }
|
||||
|
||||
File file = ffsp->open(fname, "w");
|
||||
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) {
|
||||
if (!ufs_type) { return false; }
|
||||
if (!ffs_type) { return false; }
|
||||
if (!TfsFileExists(fname)) { return false; }
|
||||
|
||||
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) {
|
||||
if (!ufs_type) { return false; }
|
||||
if (!ffs_type) { return false; }
|
||||
|
||||
if (!ffsp->remove(fname)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Delete failed"));
|
||||
|
@ -380,24 +349,48 @@ void (* const kUFSCommand[])(void) PROGMEM = {
|
|||
&UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete};
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
// UfsDelete sdcard or flashfs file if only one of them available
|
||||
// UfsDelete2 flashfs file if available
|
||||
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);
|
||||
} else {
|
||||
ResponseCmndDone();
|
||||
|
@ -418,7 +411,7 @@ const char UFS_FORM_FILE_UPLOAD[] PROGMEM =
|
|||
"<div id='f1' name='f1' style='display:block;'>"
|
||||
"<fieldset><legend><b> " D_MANAGE_FILE_SYSTEM " </b></legend>";
|
||||
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 =
|
||||
" <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>"; // 🔥
|
||||
#endif // GUI_TRASH_FILE
|
||||
|
||||
|
||||
void UfsDirectory(void) {
|
||||
if (!HttpCheckPriviledgedAccess()) { return; }
|
||||
|
||||
|
@ -461,8 +453,6 @@ void UfsDirectory(void) {
|
|||
|
||||
strcpy(ufs_path, "/");
|
||||
|
||||
|
||||
|
||||
if (Webserver->hasArg("download")) {
|
||||
String stmp = Webserver->arg("download");
|
||||
char *cp = (char*)stmp.c_str();
|
||||
|
@ -494,15 +484,14 @@ void UfsDirectory(void) {
|
|||
WSContentSendStyle();
|
||||
WSContentSend_P(UFS_FORM_FILE_UPLOAD);
|
||||
|
||||
char ts[16];
|
||||
char fs[16];
|
||||
UfsForm1000(UfsInfo(0, ufs_dir == 2 ? 1:0), ts, '.');
|
||||
UfsForm1000(UfsInfo(1, ufs_dir == 2 ? 1:0), fs, '.');
|
||||
|
||||
WSContentSend_P(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs);
|
||||
char ts[FLOATSZ];
|
||||
dtostrfd((float)UfsInfo(0, ufs_dir == 2 ? 1:0) / 1000, 3, ts);
|
||||
char fs[FLOATSZ];
|
||||
dtostrfd((float)UfsInfo(1, ufs_dir == 2 ? 1:0) / 1000, 3, fs);
|
||||
WSContentSend_PD(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -416,7 +416,123 @@ bool (* const xdrv_func_ptr[])(uint8_t) = { // Driver Function Pointers
|
|||
#endif
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
|
@ -825,7 +941,123 @@ const uint8_t kXdrvList[] = {
|
|||
#endif
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
|
|
|
@ -87,7 +87,71 @@ bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers
|
|||
#endif
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
|
|
|
@ -279,16 +279,13 @@ void ESP32Init() {
|
|||
|
||||
if (TasmotaGlobal.global_state.wifi_down) { return; }
|
||||
|
||||
TasmotaGlobal.wifi_stay_asleep = true;
|
||||
if (WiFi.getSleep() == false) {
|
||||
if (0 == Settings.flag3.sleep_normal) {
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: About to restart to put WiFi modem in sleep mode"),"BLE");
|
||||
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: Put WiFi modem in sleep mode"),"BLE");
|
||||
WiFi.setSleep(true); // Sleep
|
||||
}
|
||||
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: Initializing Blueetooth..."),"BLE");
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("%s: Initializing Bluetooth..."),"BLE");
|
||||
|
||||
if (!ESP32BLE.mode.init) {
|
||||
NimBLEDevice::init("");
|
||||
|
|
|
@ -589,17 +589,17 @@ int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){
|
|||
MI32_ReverseMAC(packet->MAC);
|
||||
uint8_t _bindkey[16] = {0x0};
|
||||
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++){
|
||||
if(memcmp(packet->MAC,MIBLEbindKeys[i].MAC,sizeof(packet->MAC))==0){
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(foundNoKey){
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: no Key found !!"));
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: No Key found !!"));
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -619,7 +619,7 @@ int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){
|
|||
|
||||
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;
|
||||
}
|
||||
#endif // USE_MI_DECRYPTION
|
||||
|
@ -660,7 +660,7 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter)
|
|||
bool _success = false;
|
||||
for (uint32_t i=0;i<MI32_TYPES;i++){ // i < sizeof(kMI32DeviceID) gives compiler warning
|
||||
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;
|
||||
_success = true;
|
||||
}
|
||||
|
@ -779,26 +779,23 @@ void MI32PreInit(void) {
|
|||
MI32.option.showRSSI = 1;
|
||||
MI32.option.ignoreBogusBattery = 1; // from advertisements
|
||||
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) {
|
||||
if (MI32.mode.init) { return; }
|
||||
|
||||
if (TasmotaGlobal.global_state.wifi_down) { return; }
|
||||
|
||||
TasmotaGlobal.wifi_stay_asleep = true;
|
||||
if (WiFi.getSleep() == false) {
|
||||
// AddLog_P(LOG_LEVEL_DEBUG,PSTR("MI32: WiFi modem not in sleep mode, BLE cannot start yet"));
|
||||
if (0 == Settings.flag3.sleep_normal) {
|
||||
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;
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Put WiFi modem in sleep mode"));
|
||||
WiFi.setSleep(true); // Sleep
|
||||
}
|
||||
|
||||
if (!MI32.mode.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.init = 1;
|
||||
MI32.period = Settings.tele_period;
|
||||
|
@ -1286,7 +1283,7 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
#endif //USE_MI_DECRYPTION
|
||||
|
@ -1459,7 +1456,7 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int RSSI
|
|||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG_SENSOR_LOG(PSTR("MI32: unexpected CGD1-packet"));
|
||||
DEBUG_SENSOR_LOG(PSTR("M32: Unexpected CGD1-packet"));
|
||||
}
|
||||
if(MIBLEsensors[_slot].eventType.raw == 0) return;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
|
@ -1491,7 +1488,7 @@ void MI32ParseResponse(char *buf, uint16_t bufsize, uint8_t addr[6], int RSSI) {
|
|||
* @param 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;){
|
||||
uint32_t ADtype = payload[i+1];
|
||||
uint32_t offset = payload[i];
|
||||
|
@ -1549,13 +1546,13 @@ void MI32HandleGenericBeacon(uint8_t* payload, size_t payloadLength, int RSSI, u
|
|||
}
|
||||
// else handle scan
|
||||
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;
|
||||
return;
|
||||
}
|
||||
for(auto _scanResult : MIBLEscanResult){
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1585,12 +1582,12 @@ void MI32addBeacon(uint8_t index, char* data){
|
|||
_new.time = 0;
|
||||
if(memcmp(_empty,_new.MAC,6) == 0){
|
||||
_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{
|
||||
_new.active = true;
|
||||
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 (MIBLEsensors.size() > XdrvMailbox.payload) {
|
||||
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.mode.canScan = 0;
|
||||
MI32.mode.canConnect = 0;
|
||||
|
@ -1875,7 +1872,7 @@ void CmndMi32Unit(void) {
|
|||
if (XdrvMailbox.data_len > 0) {
|
||||
if (MIBLEsensors.size() > XdrvMailbox.payload) {
|
||||
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.mode.canScan = 0;
|
||||
MI32.mode.canConnect = 0;
|
||||
|
@ -1925,11 +1922,11 @@ void CmndMi32Block(void){
|
|||
switch (XdrvMailbox.index) {
|
||||
case 0:
|
||||
MIBLEBlockList.clear();
|
||||
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: size of ilist: %u"), MIBLEBlockList.size());
|
||||
ResponseCmndIdxChar(PSTR("block list cleared"));
|
||||
// AddLog_P(LOG_LEVEL_INFO,PSTR("M32: Size of ilist: %u"), MIBLEBlockList.size());
|
||||
ResponseCmndIdxChar(PSTR("Block list cleared"));
|
||||
break;
|
||||
case 1:
|
||||
ResponseCmndIdxChar(PSTR("show block list"));
|
||||
ResponseCmndIdxChar(PSTR("Show block list"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1955,7 +1952,7 @@ void CmndMi32Block(void){
|
|||
ResponseCmndIdxChar(XdrvMailbox.data);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,143 +20,310 @@
|
|||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_SEESAW_SOIL
|
||||
|
||||
/*********************************************************************************************\
|
||||
* SEESAW_SOIL - Capacitance & Temperature Sensor
|
||||
* SEESAW_SOIL - Capacitice Soil Moisture & Temperature Sensor
|
||||
*
|
||||
* 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
|
||||
* otherwise the moisture value will only be emitted every TelePeriod
|
||||
* #define SEESAW_SOIL_RAW enables displaying analog capacitance input in the
|
||||
* web page for calibration purposes
|
||||
* #define SEESAW_SOIL_PERSISTENT_NAMING to get sensor names indexed by i2c address
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XSNS_81 81
|
||||
#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_START_ADDRESS 0x36
|
||||
#define SEESAW_SOIL_MAX_SENSORS 4
|
||||
#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
|
||||
uint8_t SeeSoilCount = 0; // global sensor count
|
||||
// Convert capacitance into a moisture.
|
||||
// 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 {
|
||||
Adafruit_seesaw *ss; // instance pointer
|
||||
uint16_t capacitance;
|
||||
float temperature;
|
||||
uint8_t address;
|
||||
} SeeSoil[SEESAW_SOIL_MAX_SENSORS];
|
||||
const char name[8] = "SeeSoil"; // spaces not allowed for Homeassistant integration/mqtt topics
|
||||
uint8_t count = 0; // global sensor count (0xFF = not initialized)
|
||||
uint8_t state = STATE_IDLE; // current state
|
||||
bool present = false; // driver active
|
||||
} SeeSoil;
|
||||
|
||||
// Used to convert capacitance into a moisture.
|
||||
// From observation, a free air reading is at 320
|
||||
// Immersed in tap water, reading is 1014
|
||||
// Appears to be a 10-bit device, readings close to 1020
|
||||
// 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))
|
||||
struct SEESAW_SOIL_SNS {
|
||||
uint8_t address; // i2c address
|
||||
float moisture;
|
||||
float temperature;
|
||||
#ifdef SEESAW_SOIL_RAW
|
||||
uint16_t capacitance; // raw analog reading
|
||||
#endif // SEESAW_SOIL_RAW
|
||||
} SeeSoilSNS[SEESAW_SOIL_MAX_SENSORS];
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************************************************************************\
|
||||
* i2c routines
|
||||
\*********************************************************************************************/
|
||||
|
||||
void SEESAW_SOILDetect(void) {
|
||||
Adafruit_seesaw *SSptr=0;
|
||||
|
||||
for (uint32_t i = 0; i < SEESAW_SOIL_MAX_SENSORS; i++) {
|
||||
void seeSoilInit(void) {
|
||||
for (int i = 0; i < SEESAW_SOIL_MAX_SENSORS; i++) {
|
||||
int addr = SEESAW_SOIL_START_ADDRESS + i;
|
||||
if (!I2cSetDevice(addr)) { continue; }
|
||||
|
||||
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 ( ! I2cSetDevice(addr) ) { continue; }
|
||||
seeSoilCommand(COMMAND_RESET);
|
||||
}
|
||||
if (SSptr) {
|
||||
delete SSptr; // used object for detection, didn't find anything so we don't need this object
|
||||
SeeSoil.state = STATE_RESET;
|
||||
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
|
||||
#ifdef SEESAW_SOIL_PUBLISH
|
||||
uint32_t old_moist;
|
||||
#endif // SEESAW_SOIL_PUBLISH
|
||||
void seeSoilCommand(uint32_t command) { // issue commands to sensors
|
||||
uint8_t regLow;
|
||||
uint8_t regHigh = SEESAW_STATUS_BASE;
|
||||
uint32_t count = SeeSoil.count;
|
||||
|
||||
for (uint32_t i = 0; i < SeeSoilCount; i++) {
|
||||
SeeSoil[i].temperature = ConvertTemp(SeeSoil[i].ss->getTemp());
|
||||
#ifdef SEESAW_SOIL_PUBLISH
|
||||
old_moist = uint32_t (CAP_TO_MOIST(SeeSoil[i].capacitance)*100);
|
||||
#endif // SEESAW_SOIL_PUBLISH
|
||||
SeeSoil[i].capacitance = SeeSoil[i].ss->touchRead(0);
|
||||
#ifdef SEESAW_SOIL_PUBLISH
|
||||
if (uint32_t (CAP_TO_MOIST(SeeSoil[i].capacitance)*100) != old_moist) {
|
||||
Response_P(PSTR("{")); // send values to MQTT & rules
|
||||
SEESAW_SOILJson(i);
|
||||
ResponseJsonEnd();
|
||||
MqttPublishTeleSensor();
|
||||
switch (command) {
|
||||
case COMMAND_RESET:
|
||||
count = SEESAW_SOIL_MAX_SENSORS;
|
||||
regLow = SEESAW_STATUS_SWRST;
|
||||
break;
|
||||
case COMMAND_ID:
|
||||
count = SEESAW_SOIL_MAX_SENSORS;
|
||||
regLow = SEESAW_STATUS_HW_ID;
|
||||
break;
|
||||
case COMMAND_TEMP:
|
||||
regLow = SEESAW_STATUS_TEMP;
|
||||
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 sensor_name[sizeof(SeeSoilName) + 3];
|
||||
char sensor_name[sizeof(SeeSoil.name) + 3];
|
||||
|
||||
for (uint32_t i = 0; i < SeeSoilCount; i++) {
|
||||
dtostrfd(SeeSoil[i].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
SEESAW_SOILName(i, sensor_name, sizeof(sensor_name));
|
||||
for (uint32_t i = 0; i < SeeSoil.count; i++) {
|
||||
dtostrfd(SeeSoilSNS[i].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
seeSoilName(i, sensor_name, sizeof(sensor_name));
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",")); // compose tele json
|
||||
SEESAW_SOILJson(i);
|
||||
ResponseAppend_P(PSTR(",")); // compose tele json
|
||||
seeSoilJson(i);
|
||||
if (0 == TasmotaGlobal.tele_period) {
|
||||
#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
|
||||
#ifdef USE_KNX
|
||||
KnxSensor(KNX_TEMPERATURE, SeeSoil[i].temperature);
|
||||
KnxSensor(KNX_HUMIDITY, CAP_TO_MOIST(SeeSoil[i].capacitance) * 100);
|
||||
KnxSensor(KNX_TEMPERATURE, SeeSoilSNS[i].temperature);
|
||||
KnxSensor(KNX_HUMIDITY, SeeSoilSNS[i].moisture);
|
||||
#endif // USE_KNX
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
#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
|
||||
WSContentSend_PD(HTTP_SNS_MOISTURE, sensor_name,
|
||||
uint32_t (CAP_TO_MOIST(SeeSoil[i].capacitance)*100)); // web page formats as integer (%d) percent
|
||||
WSContentSend_PD(HTTP_SNS_MOISTURE, sensor_name, (uint32_t) SeeSoilSNS[i].moisture);
|
||||
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, temperature, TempUnit());
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
} // for each sensor connected
|
||||
}
|
||||
|
||||
void SEESAW_SOILJson(int no) { // common json
|
||||
void seeSoilJson(int no) { // common json
|
||||
char temperature[FLOATSZ];
|
||||
char sensor_name[sizeof(SeeSoilName) + 3];
|
||||
char sensor_name[sizeof(SeeSoil.name) + 3];
|
||||
|
||||
SEESAW_SOILName(no, sensor_name, sizeof(sensor_name));
|
||||
dtostrfd(SeeSoil[no].temperature, Settings.flag2.temperature_resolution, temperature);
|
||||
seeSoilName(no, sensor_name, sizeof(sensor_name));
|
||||
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}"),
|
||||
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) {
|
||||
snprintf_P(name, len, PSTR("%s%c%u"), SeeSoilName, IndexSeparator(), no + 1);
|
||||
#ifdef SEESAW_SOIL_PERSISTENT_NAMING
|
||||
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 {
|
||||
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;
|
||||
|
||||
if (FUNC_INIT == function) {
|
||||
SEESAW_SOILDetect();
|
||||
seeSoilInit();
|
||||
}
|
||||
else if (SeeSoilCount){
|
||||
else if (SeeSoil.present){
|
||||
switch (function) {
|
||||
case FUNC_EVERY_SECOND:
|
||||
SEESAW_SOILEverySecond();
|
||||
case FUNC_EVERY_50_MSECOND:
|
||||
seeSoilEvery50ms();
|
||||
break;
|
||||
#ifdef SEESAW_SOIL_PUBLISH
|
||||
case FUNC_EVERY_SECOND:
|
||||
seeSoilEverySecond();
|
||||
break;
|
||||
#endif // SEESAW_SOIL_PUBLISH
|
||||
case FUNC_JSON_APPEND:
|
||||
SEESAW_SOILShow(1);
|
||||
seeSoilShow(1);
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
SEESAW_SOILShow(0);
|
||||
seeSoilShow(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
|
|
@ -825,27 +825,144 @@ const uint8_t kXsnsList[] = {
|
|||
#endif
|
||||
|
||||
#ifdef XSNS_99
|
||||
XSNS_99
|
||||
XSNS_99,
|
||||
#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)) {
|
||||
#ifdef XFUNC_PTR_IN_ROM
|
||||
uint32_t index = pgm_read_byte(kXsnsList + sns_index);
|
||||
#else
|
||||
uint32_t index = kXsnsList[sns_index];
|
||||
#endif
|
||||
return bitRead(Settings.sensors[index / 32], index % 32);
|
||||
if (index < MAX_XSNS_DRIVERS) {
|
||||
return bitRead(Settings.sensors[index / 32], index % 32);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void XsnsSensorState(void)
|
||||
{
|
||||
void XsnsSensorState(void) {
|
||||
ResponseAppend_P(PSTR("\"")); // Use string for enable/disable signal
|
||||
for (uint32_t i = 0; i < sizeof(kXsnsList); i++) {
|
||||
#ifdef XFUNC_PTR_IN_ROM
|
||||
|
@ -866,8 +983,7 @@ void XsnsSensorState(void)
|
|||
* 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) {
|
||||
xsns_index = 0;
|
||||
return false;
|
||||
|
@ -891,8 +1007,7 @@ bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index)
|
|||
return xsns_func_ptr[xsns_index](Function);
|
||||
}
|
||||
|
||||
bool XsnsCall(uint8_t Function)
|
||||
{
|
||||
bool XsnsCall(uint8_t Function) {
|
||||
bool result = false;
|
||||
|
||||
DEBUG_TRACE_LOG(PSTR("SNS: %d"), Function);
|
||||
|
|
Loading…
Reference in New Issue