mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4841e42286 | ||
|
|
df1c227f2c | ||
|
|
06008fcf6c | ||
|
|
15c4a3e9a5 | ||
|
|
89f1fc8282 | ||
|
|
ca083166a1 | ||
|
|
ed177396b2 | ||
|
|
6dd901880e | ||
|
|
d9b577d944 | ||
|
|
324a6da0d5 | ||
|
|
391fecadd0 | ||
|
|
4d0032441f | ||
|
|
8e59460845 | ||
|
|
4b6c676992 | ||
|
|
0237cc1ca4 | ||
|
|
fbef1ca69a | ||
|
|
3b4bfaa319 | ||
|
|
2b6a986c4a | ||
|
|
494827299c | ||
|
|
a920e89ea2 | ||
|
|
6a4b7a1ac7 | ||
|
|
621c73ab03 | ||
|
|
ac7003124e | ||
|
|
4208c3551a | ||
|
|
1938c93faf | ||
|
|
2a070ef55f | ||
|
|
0c17e8deb3 | ||
|
|
22b4b66cff | ||
|
|
942d062506 | ||
|
|
7c3b8954fe | ||
|
|
bf90056c61 | ||
|
|
bcd79bc250 | ||
|
|
07c7ef22cf | ||
|
|
6d420662e1 | ||
|
|
fca458687e | ||
|
|
e34620e1e8 | ||
|
|
bcdb49ffff | ||
|
|
ebb71c7724 | ||
|
|
b8dca3db32 | ||
|
|
94d704730f | ||
|
|
0c76ed2c4c | ||
|
|
8bac9f687e | ||
|
|
56b597d45f | ||
|
|
96b83e3eb3 | ||
|
|
e21ad6a6ba | ||
|
|
7fe4b99cef | ||
|
|
0c8dd1d8cf | ||
|
|
cafc6103ea | ||
|
|
6d3feaf81c | ||
|
|
c8d8b50d47 | ||
|
|
0c89d90d56 | ||
|
|
d0fc09fc01 | ||
|
|
c8b6d1e69c | ||
|
|
49d719770c | ||
|
|
c75a1c9e1e | ||
|
|
da7b0e9597 | ||
|
|
8f1243850f | ||
|
|
b931e282f2 | ||
|
|
66df8031ed | ||
|
|
966f82e38c | ||
|
|
118cbd9224 | ||
|
|
def585fa04 | ||
|
|
56a3dfd41a | ||
|
|
cc0f4c43ae | ||
|
|
c341148009 | ||
|
|
9089e5d334 | ||
|
|
720a82b3da | ||
|
|
a83d3a12fb | ||
|
|
1dae9f8beb | ||
|
|
e25d6e4d0b | ||
|
|
c01c098f7e | ||
|
|
fecfe9d791 | ||
|
|
b996c4dcf6 | ||
|
|
273efbcb65 | ||
|
|
7d177ca049 | ||
|
|
83f46ffd6c | ||
|
|
03e43ba839 | ||
|
|
71dfc0e1eb | ||
|
|
355b71cacf | ||
|
|
c660440996 | ||
|
|
70033017fd | ||
|
|
b9c08a58ad | ||
|
|
4db69760c6 | ||
|
|
8ec0731ca2 | ||
|
|
25b1957dbf | ||
|
|
f2dbc26491 | ||
|
|
fd11a09882 |
65
CHANGELOG.md
65
CHANGELOG.md
@@ -5,12 +5,68 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [3.0.1] March 30 2021
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- power settings, disabling BLE and turning off Wifi sleep
|
||||||
|
- Rx and Tx counts to Heartbeat MQTT payload
|
||||||
|
- ethernet support
|
||||||
|
- id to info command to show only a heatingcircuit
|
||||||
|
- add sending devices that are not listed to 0x07
|
||||||
|
- extra MQTT boolean option for "ON" and "OFF"
|
||||||
|
- support for chunked MQTT payloads to allow large data sets > 2kb
|
||||||
|
- external Button support (#708) for resetting to factory defaults and other actions
|
||||||
|
- new console set command in `system`, `set board_profile <profile>` for quickly enabling cabled ethernet connections without using the captive wifi portal
|
||||||
|
- added in MQTT nested mode, for thermostat and mixer, like we had back in v2
|
||||||
|
- cascade MC400 (product-id 210) (3.0.0b6), power values for heating sources (3.0.1b1)
|
||||||
|
- values for wwMaxPower, wwFlowtempOffset
|
||||||
|
- RC300 `thermostat temp -1` to clear temporary setpoint in auto mode
|
||||||
|
- syslog port selectable (#744)
|
||||||
|
- individual mqtt commands (#31)
|
||||||
|
- board Profiles (#11)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- telegrams matched to masterthermostat 0x18
|
||||||
|
- multiple roomcontrollers
|
||||||
|
- readback after write with delay (give ems-devices time to set the value)
|
||||||
|
- thermostat ES72/RC20 device 66 to command-set RC20_2
|
||||||
|
- MQTT payloads not adding to queue when MQTT is re-connecting (fixes #369)
|
||||||
|
- fix for HA topics with invalid command formats (#728)
|
||||||
|
- wrong position of values #723, #732
|
||||||
|
- OTA Upload via Web on OSX
|
||||||
|
- Rx and Tx quality % would sometimes show > 100
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- changed how telegram parameters are rendered for mqtt, console and web (#632)
|
||||||
|
- split `show values` in smaller packages (edited)
|
||||||
|
- extended length of IP/hostname from 32 to 48 chars (#676)
|
||||||
|
- check flowsensor for `tap_water_active`
|
||||||
|
- mqtt prefixed with `Base`
|
||||||
|
- count Dallas sensor fails
|
||||||
|
- switch from SPIFFS to LITTLEFS
|
||||||
|
- added ID to MQTT payloads which is the Device's product ID and used in HA to identify a unique HA device
|
||||||
|
- increased MQTT buffer and reduced wait time between publishes
|
||||||
|
- updated to the latest ArduinoJson library
|
||||||
|
- some names of mqtt-tags like in v2.2.1
|
||||||
|
- new ESP32 partition side to allow for smoother OTA and fallback
|
||||||
|
- network Gateway IP is optional (#682)emsesp/EMS-ESP
|
||||||
|
- moved to a new GitHub repo https://github.com/emsesp/EMS-ESP32
|
||||||
|
- invert LED changed to Hide LED. Default is off.
|
||||||
|
- renamed Scan Network to Scan WiFi Network
|
||||||
|
- added version to cmd=settings
|
||||||
|
- Allow both WiFi and Ethernet together, fall back to AP when Ethernet disconnects
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- Shower Alert (disabled for now)
|
||||||
|
|
||||||
## [3.0.0] March 18 2021
|
## [3.0.0] March 18 2021
|
||||||
|
|
||||||
## **ESP32 version based off ESP-ESP v2.1**
|
|
||||||
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Power settings, disabling BLE and turning off Wifi sleep
|
- Power settings, disabling BLE and turning off Wifi sleep
|
||||||
- Rx and Tx counts to Heartbeat MQTT payload
|
- Rx and Tx counts to Heartbeat MQTT payload
|
||||||
- Ethernet support
|
- Ethernet support
|
||||||
@@ -27,6 +83,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Syslog port selectable (#744)
|
- Syslog port selectable (#744)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- telegrams matched to masterthermostat 0x18
|
- telegrams matched to masterthermostat 0x18
|
||||||
- multiple roomcontrollers
|
- multiple roomcontrollers
|
||||||
- readback after write with delay (give ems-devices time to set the value)
|
- readback after write with delay (give ems-devices time to set the value)
|
||||||
@@ -37,6 +94,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- OTA Upload via Web on OSX
|
- OTA Upload via Web on OSX
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- changed how telegram parameters are rendered for mqtt, console and web (#632)
|
- changed how telegram parameters are rendered for mqtt, console and web (#632)
|
||||||
- split `show values` in smaller packages (edited)
|
- split `show values` in smaller packages (edited)
|
||||||
- extended length of IP/hostname from 32 to 48 chars (#676)
|
- extended length of IP/hostname from 32 to 48 chars (#676)
|
||||||
@@ -51,4 +109,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- new ESP32 partition side to allow for smoother OTA and fallback
|
- new ESP32 partition side to allow for smoother OTA and fallback
|
||||||
- Network Gateway IP is optional (#682)emsesp/EMS-ESP
|
- Network Gateway IP is optional (#682)emsesp/EMS-ESP
|
||||||
- moved to a new GitHub repo https://github.com/emsesp/EMS-ESP32
|
- moved to a new GitHub repo https://github.com/emsesp/EMS-ESP32
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
### Added
|
## Added
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
### Fixed
|
## Changed
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
# Change the IP address to that of your ESP device to enable local development of the UI.
|
# Change the IP address to that of your ESP device to enable local development of the UI.
|
||||||
# Remember to also enable CORS in platformio.ini before uploading the code to the device.
|
# Remember to also enable CORS in platformio.ini before uploading the code to the device
|
||||||
|
# with -DENABLE_CORS
|
||||||
|
|
||||||
# ESP32 dev
|
# my Wifi
|
||||||
REACT_APP_HTTP_ROOT=http://10.10.10.101
|
#REACT_APP_HTTP_ROOT=http://10.10.10.101
|
||||||
REACT_APP_WEB_SOCKET_ROOT=ws://10.10.10.101
|
#REACT_APP_WEB_SOCKET_ROOT=ws://10.10.10.101
|
||||||
|
|
||||||
# ESP8266 dev
|
# my Ethernet
|
||||||
#REACT_APP_HTTP_ROOT=http://10.10.10.140
|
REACT_APP_HTTP_ROOT=http://192.168.1.134
|
||||||
#REACT_APP_WEB_SOCKET_ROOT=ws://10.10.10.140
|
REACT_APP_WEB_SOCKET_ROOT=ws://http://192.168.1.134
|
||||||
|
|||||||
20166
interface/package-lock.json
generated
20166
interface/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ class App extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<CustomMuiTheme>
|
<CustomMuiTheme>
|
||||||
<SnackbarProvider maxSnack={3} anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
<SnackbarProvider autoHideDuration={3000} maxSnack={3} anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
||||||
ref={this.notistackRef}
|
ref={this.notistackRef}
|
||||||
action={(key) => (
|
action={(key) => (
|
||||||
<IconButton onClick={this.onClickDismiss(key)} size="small">
|
<IconButton onClick={this.onClickDismiss(key)} size="small">
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class APSettingsForm extends React.Component<APSettingsFormProps> {
|
|||||||
onChange={handleValueChange('provision_mode')}
|
onChange={handleValueChange('provision_mode')}
|
||||||
margin="normal">
|
margin="normal">
|
||||||
<MenuItem value={APProvisionMode.AP_MODE_ALWAYS}>Always</MenuItem>
|
<MenuItem value={APProvisionMode.AP_MODE_ALWAYS}>Always</MenuItem>
|
||||||
<MenuItem value={APProvisionMode.AP_MODE_DISCONNECTED}>When WiFi Disconnected</MenuItem>
|
<MenuItem value={APProvisionMode.AP_MODE_DISCONNECTED}>When Network Disconnected</MenuItem>
|
||||||
<MenuItem value={APProvisionMode.AP_NEVER}>Never</MenuItem>
|
<MenuItem value={APProvisionMode.AP_NEVER}>Never</MenuItem>
|
||||||
</SelectValidator>
|
</SelectValidator>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,6 +173,17 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
|
|||||||
<MenuItem value={3}>1/0</MenuItem>
|
<MenuItem value={3}>1/0</MenuItem>
|
||||||
<MenuItem value={4}>"ON"/"OFF"</MenuItem>
|
<MenuItem value={4}>"ON"/"OFF"</MenuItem>
|
||||||
</SelectValidator>
|
</SelectValidator>
|
||||||
|
<SelectValidator name="subscribe_format"
|
||||||
|
label="Subscribe Format"
|
||||||
|
value={data.subscribe_format}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={handleValueChange('subscribe_format')}
|
||||||
|
margin="normal">
|
||||||
|
<MenuItem value={0}>general device topic</MenuItem>
|
||||||
|
<MenuItem value={1}>individual topics, main heating circuit</MenuItem>
|
||||||
|
<MenuItem value={2}>individual topics, all heating circuits</MenuItem>
|
||||||
|
</SelectValidator>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
|||||||
@@ -41,4 +41,5 @@ export interface MqttSettings {
|
|||||||
ha_enabled: boolean;
|
ha_enabled: boolean;
|
||||||
ha_climate_format: number;
|
ha_climate_format: number;
|
||||||
nested_format: boolean;
|
nested_format: boolean;
|
||||||
|
subscribe_format: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class NetworkConnection extends Component<NetworkConnectionProps, NetworkConnect
|
|||||||
<MenuAppBar sectionTitle="Network Connection">
|
<MenuAppBar sectionTitle="Network Connection">
|
||||||
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
|
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
|
||||||
<Tab value="/network/status" label="Network Status" />
|
<Tab value="/network/status" label="Network Status" />
|
||||||
<Tab value="/network/scan" label="Scan Networks" disabled={!authenticatedContext.me.admin} />
|
<Tab value="/network/scan" label="Scan WiFi Networks" disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab value="/network/settings" label="Network Settings" disabled={!authenticatedContext.me.admin} />
|
<Tab value="/network/settings" label="Network Settings" disabled={!authenticatedContext.me.admin} />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { TextValidator, SelectValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
||||||
|
|
||||||
import { Checkbox, List, ListItem, ListItemText, ListItemAvatar, ListItemSecondaryAction } from '@material-ui/core';
|
import { Checkbox, List, ListItem, ListItemText, ListItemAvatar, ListItemSecondaryAction } from '@material-ui/core';
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@ import LockIcon from '@material-ui/icons/Lock';
|
|||||||
import LockOpenIcon from '@material-ui/icons/LockOpen';
|
import LockOpenIcon from '@material-ui/icons/LockOpen';
|
||||||
import DeleteIcon from '@material-ui/icons/Delete';
|
import DeleteIcon from '@material-ui/icons/Delete';
|
||||||
import SaveIcon from '@material-ui/icons/Save';
|
import SaveIcon from '@material-ui/icons/Save';
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
|
||||||
|
|
||||||
import { RestFormProps, PasswordValidator, BlockFormControlLabel, FormActions, FormButton } from '../components';
|
import { RestFormProps, PasswordValidator, BlockFormControlLabel, FormActions, FormButton } from '../components';
|
||||||
import { isIP, isHostname, optional } from '../validators';
|
import { isIP, isHostname, optional } from '../validators';
|
||||||
@@ -34,7 +33,6 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
|
|||||||
ssid: selectedNetwork.ssid,
|
ssid: selectedNetwork.ssid,
|
||||||
password: "",
|
password: "",
|
||||||
hostname: props.data.hostname,
|
hostname: props.data.hostname,
|
||||||
ethernet_profile: 0,
|
|
||||||
static_ip_config: false,
|
static_ip_config: false,
|
||||||
}
|
}
|
||||||
props.setData(networkSettings);
|
props.setData(networkSettings);
|
||||||
@@ -86,7 +84,7 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
|
|||||||
validators={['matchRegexp:^.{0,32}$']}
|
validators={['matchRegexp:^.{0,32}$']}
|
||||||
errorMessages={['SSID must be 32 characters or less']}
|
errorMessages={['SSID must be 32 characters or less']}
|
||||||
name="ssid"
|
name="ssid"
|
||||||
label="SSID"
|
label="SSID (leave blank to disable WiFi)"
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={data.ssid}
|
value={data.ssid}
|
||||||
@@ -119,17 +117,6 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
|
|||||||
onChange={handleValueChange('hostname')}
|
onChange={handleValueChange('hostname')}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<SelectValidator name="ems_bus_id"
|
|
||||||
label="Ethernet Profile"
|
|
||||||
value={data.ethernet_profile}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
onChange={handleValueChange('ethernet_profile')}
|
|
||||||
margin="normal">
|
|
||||||
<MenuItem value={0}>None (wifi only)</MenuItem>
|
|
||||||
<MenuItem value={1}>Profile 1 (LAN8720)</MenuItem>
|
|
||||||
<MenuItem value={2}>Profile 2 (TLK110)</MenuItem>
|
|
||||||
</SelectValidator>
|
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export interface NetworkSettings {
|
|||||||
ssid: string;
|
ssid: string;
|
||||||
password: string;
|
password: string;
|
||||||
hostname: string;
|
hostname: string;
|
||||||
ethernet_profile: number;
|
|
||||||
static_ip_config: boolean;
|
static_ip_config: boolean;
|
||||||
local_ip?: string;
|
local_ip?: string;
|
||||||
gateway_ip?: string;
|
gateway_ip?: string;
|
||||||
|
|||||||
23
interface/src/project/EMSESPBoardProfiles.tsx
Normal file
23
interface/src/project/EMSESPBoardProfiles.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
|
||||||
|
type BoardProfiles = {
|
||||||
|
[name: string]: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BOARD_PROFILES: BoardProfiles = {
|
||||||
|
"S32": "BBQKees Gateway S32",
|
||||||
|
"E32": "BBQKees Gateway E32",
|
||||||
|
"NODEMCU": "NodeMCU 32S",
|
||||||
|
"MT-ET": "MT-ET Live D1 Mini",
|
||||||
|
"LOLIN": "Lolin D32",
|
||||||
|
"OLIMEX": "Olimex ESP32-EVB",
|
||||||
|
"TLK110": "Generic Ethernet (TLK110)",
|
||||||
|
"LAN8720": "Generic Ethernet (LAN8720)"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function boardProfileSelectItems() {
|
||||||
|
return Object.keys(BOARD_PROFILES).map(code => (
|
||||||
|
<MenuItem key={code} value={code}>{BOARD_PROFILES[code]}</MenuItem>
|
||||||
|
));
|
||||||
|
}
|
||||||
@@ -2,40 +2,19 @@ import React, { Component, Fragment } from "react";
|
|||||||
import { withStyles, Theme, createStyles } from "@material-ui/core/styles";
|
import { withStyles, Theme, createStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table, TableBody, TableCell, TableHead, TableRow, TableContainer, withWidth, WithWidthProps, isWidthDown,
|
||||||
TableBody,
|
Button, Tooltip, DialogTitle, DialogContent, DialogActions, Box, Dialog, Typography
|
||||||
TableCell,
|
|
||||||
TableHead,
|
|
||||||
TableRow,
|
|
||||||
TableContainer,
|
|
||||||
withWidth,
|
|
||||||
WithWidthProps,
|
|
||||||
isWidthDown,
|
|
||||||
Button,
|
|
||||||
Tooltip,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
Box,
|
|
||||||
Dialog,
|
|
||||||
Typography,
|
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
|
||||||
import RefreshIcon from "@material-ui/icons/Refresh";
|
import RefreshIcon from "@material-ui/icons/Refresh";
|
||||||
import ListIcon from "@material-ui/icons/List";
|
import ListIcon from "@material-ui/icons/List";
|
||||||
|
|
||||||
import {
|
import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from "../authentication";
|
||||||
redirectingAuthorizedFetch,
|
|
||||||
withAuthenticatedContext,
|
|
||||||
AuthenticatedContextProps,
|
|
||||||
} from "../authentication";
|
|
||||||
|
|
||||||
import { RestFormProps, FormButton } from "../components";
|
import { RestFormProps, FormButton } from "../components";
|
||||||
|
|
||||||
import { EMSESPDevices, EMSESPDeviceData, Device } from "./EMSESPtypes";
|
import { EMSESPDevices, EMSESPDeviceData, Device } from "./EMSESPtypes";
|
||||||
|
|
||||||
import { ENDPOINT_ROOT } from "../api";
|
import { ENDPOINT_ROOT } from "../api";
|
||||||
|
|
||||||
export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + "scanDevices";
|
export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + "scanDevices";
|
||||||
export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + "deviceData";
|
export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + "deviceData";
|
||||||
|
|
||||||
@@ -73,22 +52,19 @@ type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> &
|
|||||||
|
|
||||||
function formatTemp(t: string) {
|
function formatTemp(t: string) {
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
return "(not available)";
|
return "n/a";
|
||||||
}
|
}
|
||||||
return t + " °C";
|
return t + " °C";
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatUnit(u: string) {
|
function formatUnit(u: string) {
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
return " " + u;
|
return " " + u;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EMSESPDevicesForm extends Component<
|
class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesFormState> {
|
||||||
EMSESPDevicesFormProps,
|
|
||||||
EMSESPDevicesFormState
|
|
||||||
> {
|
|
||||||
state: EMSESPDevicesFormState = {
|
state: EMSESPDevicesFormState = {
|
||||||
confirmScanDevices: false,
|
confirmScanDevices: false,
|
||||||
processing: false,
|
processing: false,
|
||||||
@@ -106,7 +82,7 @@ class EMSESPDevicesForm extends Component<
|
|||||||
return (this.state.deviceData?.data || []).length === 0;
|
return (this.state.deviceData?.data || []).length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
createDeviceItems() {
|
renderDeviceItems() {
|
||||||
const { width, data } = this.props;
|
const { width, data } = this.props;
|
||||||
return (
|
return (
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
@@ -186,7 +162,7 @@ class EMSESPDevicesForm extends Component<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSensorItems() {
|
renderSensorItems() {
|
||||||
const { data } = this.props;
|
const { data } = this.props;
|
||||||
return (
|
return (
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
@@ -304,7 +280,6 @@ class EMSESPDevicesForm extends Component<
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
return response.json();
|
return response.json();
|
||||||
// this.setState({ errorMessage: undefined }, this.props.loadData);
|
|
||||||
}
|
}
|
||||||
throw Error("Unexpected response code: " + response.status);
|
throw Error("Unexpected response code: " + response.status);
|
||||||
})
|
})
|
||||||
@@ -365,11 +340,11 @@ class EMSESPDevicesForm extends Component<
|
|||||||
</TableContainer>
|
</TableContainer>
|
||||||
)}
|
)}
|
||||||
{this.noDeviceData() && (
|
{this.noDeviceData() && (
|
||||||
<Box color="warning.main" p={0} mt={0} mb={0}>
|
<Box color="warning.main" p={0} mt={0} mb={0}>
|
||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
<i>No data available for this device</i>
|
<i>No data available for this device</i>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Fragment >
|
</Fragment >
|
||||||
);
|
);
|
||||||
@@ -379,9 +354,9 @@ class EMSESPDevicesForm extends Component<
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<br></br>
|
<br></br>
|
||||||
{this.createDeviceItems()}
|
{this.renderDeviceItems()}
|
||||||
{this.renderDeviceData()}
|
{this.renderDeviceData()}
|
||||||
{this.createSensorItems()}
|
{this.renderSensorItems()}
|
||||||
<br></br>
|
<br></br>
|
||||||
<Box display="flex" flexWrap="wrap">
|
<Box display="flex" flexWrap="wrap">
|
||||||
<Box flexGrow={1} padding={1}>
|
<Box flexGrow={1} padding={1}>
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { ValidatorForm, TextValidator, SelectValidator } from 'react-material-ui-form-validator';
|
// import { Container } from '@material-ui/core';
|
||||||
|
|
||||||
import { Checkbox, Typography, Box, Link } from '@material-ui/core';
|
|
||||||
import SaveIcon from '@material-ui/icons/Save';
|
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
|
||||||
|
|
||||||
import { ENDPOINT_ROOT } from '../api';
|
import { ENDPOINT_ROOT } from '../api';
|
||||||
import { restController, RestControllerProps, RestFormLoader, RestFormProps, FormActions, FormButton, BlockFormControlLabel, SectionContent } from '../components';
|
import EMSESPSettingsForm from './EMSESPSettingsForm';
|
||||||
|
|
||||||
import { isIP, optional } from '../validators';
|
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
|
||||||
|
|
||||||
import { EMSESPSettings } from './EMSESPtypes';
|
import { EMSESPSettings } from './EMSESPtypes';
|
||||||
|
|
||||||
@@ -19,303 +15,24 @@ type EMSESPSettingsControllerProps = RestControllerProps<EMSESPSettings>;
|
|||||||
class EMSESPSettingsController extends Component<EMSESPSettingsControllerProps> {
|
class EMSESPSettingsController extends Component<EMSESPSettingsControllerProps> {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP));
|
|
||||||
this.props.loadData();
|
this.props.loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SectionContent title='EMS-ESP Settings' titleGutter>
|
// <Container maxWidth="md" disableGutters>
|
||||||
|
<SectionContent title='' titleGutter>
|
||||||
<RestFormLoader
|
<RestFormLoader
|
||||||
{...this.props}
|
{...this.props}
|
||||||
render={props => (
|
render={formProps => (
|
||||||
<EMSESPSettingsControllerForm {...props} />
|
<EMSESPSettingsForm {...formProps} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
// </Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default restController(EMSESP_SETTINGS_ENDPOINT, EMSESPSettingsController);
|
export default restController(EMSESP_SETTINGS_ENDPOINT, EMSESPSettingsController);
|
||||||
|
|
||||||
type EMSESPSettingsControllerFormProps = RestFormProps<EMSESPSettings>;
|
|
||||||
|
|
||||||
function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps) {
|
|
||||||
const { data, saveData, handleValueChange } = props;
|
|
||||||
return (
|
|
||||||
<ValidatorForm onSubmit={saveData}>
|
|
||||||
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
|
|
||||||
<Typography variant="body1">
|
|
||||||
Change the default settings on this page. For help click <Link target="_blank" href="https://emsesp.github.io/docs/#/Configure-firmware?id=settings" color="primary">{'here'}</Link>.
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
EMS Bus
|
|
||||||
</Typography>
|
|
||||||
<SelectValidator name="tx_mode"
|
|
||||||
label="Tx Mode"
|
|
||||||
value={data.tx_mode}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
onChange={handleValueChange('tx_mode')}
|
|
||||||
margin="normal">
|
|
||||||
<MenuItem value={0}>0 - Off</MenuItem>
|
|
||||||
<MenuItem value={1}>1 - Default</MenuItem>
|
|
||||||
<MenuItem value={2}>2 - EMS+</MenuItem>
|
|
||||||
<MenuItem value={3}>3 - HT3</MenuItem>
|
|
||||||
<MenuItem value={4}>4 - Hardware</MenuItem>
|
|
||||||
</SelectValidator>
|
|
||||||
<SelectValidator name="ems_bus_id"
|
|
||||||
label="Bus ID"
|
|
||||||
value={data.ems_bus_id}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
onChange={handleValueChange('ems_bus_id')}
|
|
||||||
margin="normal">
|
|
||||||
<MenuItem value={0x0B}>Service Key (0x0B)</MenuItem>
|
|
||||||
<MenuItem value={0x0D}>Modem (0x0D)</MenuItem>
|
|
||||||
<MenuItem value={0x0A}>Terminal (0x0A)</MenuItem>
|
|
||||||
<MenuItem value={0x0F}>Time Module (0x0F)</MenuItem>
|
|
||||||
<MenuItem value={0x12}>Alarm Module (0x12)</MenuItem>
|
|
||||||
</SelectValidator>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
|
||||||
errorMessages={['Rx GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
|
||||||
name="rx_gpio"
|
|
||||||
label="Rx GPIO pin"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.rx_gpio}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('rx_gpio')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
|
||||||
errorMessages={['Tx GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
|
||||||
name="tx_gpio"
|
|
||||||
label="Tx GPIO pin"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.tx_gpio}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('tx_gpio')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:120']}
|
|
||||||
errorMessages={['Tx delay is required', "Must be a number", "Must be 0 or higher", "Max value is 120"]}
|
|
||||||
name="tx_delay"
|
|
||||||
label="Tx delayed start (seconds)"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.tx_delay}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('tx_delay')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
External Button
|
|
||||||
</Typography>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
|
||||||
errorMessages={['Button GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
|
||||||
name="pbutton_gpio"
|
|
||||||
label="Button GPIO pin"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.pbutton_gpio}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('pbutton_gpio')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
Dallas Sensor
|
|
||||||
</Typography>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
|
||||||
errorMessages={['Dallas GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
|
||||||
name="dallas_gpio"
|
|
||||||
label="Dallas GPIO pin (0=none)"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.dallas_gpio}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('dallas_gpio')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.dallas_parasite}
|
|
||||||
onChange={handleValueChange('dallas_parasite')}
|
|
||||||
value="dallas_parasite"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Dallas Parasite Mode"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
LED
|
|
||||||
</Typography>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
|
||||||
errorMessages={['LED GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
|
||||||
name="led_gpio"
|
|
||||||
label="LED GPIO pin (0=none)"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.led_gpio}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('led_gpio')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.hide_led}
|
|
||||||
onChange={handleValueChange('hide_led')}
|
|
||||||
value="hide_led"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Invert/Hide LED"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
Shower
|
|
||||||
</Typography>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.shower_timer}
|
|
||||||
onChange={handleValueChange('shower_timer')}
|
|
||||||
value="shower_timer"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Shower Timer"
|
|
||||||
/>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.shower_alert}
|
|
||||||
onChange={handleValueChange('shower_alert')}
|
|
||||||
value="shower_alert"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Shower Alert"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
API
|
|
||||||
</Typography>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.api_enabled}
|
|
||||||
onChange={handleValueChange('api_enabled')}
|
|
||||||
value="api_enabled"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Allow WEB API to write commands"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
Syslog
|
|
||||||
</Typography>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.syslog_enabled}
|
|
||||||
onChange={handleValueChange('syslog_enabled')}
|
|
||||||
value="syslog_enabled"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Enable Syslog"
|
|
||||||
/>
|
|
||||||
<TextValidator
|
|
||||||
validators={['isOptionalIP']}
|
|
||||||
errorMessages={["Not a valid IP address"]}
|
|
||||||
name="syslog_host"
|
|
||||||
label="Syslog IP"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.syslog_host}
|
|
||||||
onChange={handleValueChange('syslog_host')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
|
|
||||||
errorMessages={['Port is required', "Must be a number", "Must be greater than 0 ", "Max value is 65535"]}
|
|
||||||
name="syslog_port"
|
|
||||||
label="Syslog Port (default 514)"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.syslog_port}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('syslog_port')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<SelectValidator name="syslog_level"
|
|
||||||
label="Syslog Log Level"
|
|
||||||
value={data.syslog_level}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
onChange={handleValueChange('syslog_level')}
|
|
||||||
margin="normal">
|
|
||||||
<MenuItem value={-1}>OFF</MenuItem>
|
|
||||||
<MenuItem value={3}>ERR</MenuItem>
|
|
||||||
<MenuItem value={5}>NOTICE</MenuItem>
|
|
||||||
<MenuItem value={6}>INFO</MenuItem>
|
|
||||||
<MenuItem value={7}>DEBUG</MenuItem>
|
|
||||||
<MenuItem value={8}>ALL</MenuItem>
|
|
||||||
</SelectValidator>
|
|
||||||
<TextValidator
|
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
|
|
||||||
errorMessages={['Syslog Mark is required', "Must be a number", "Must be 0 or higher", "Max value is 10"]}
|
|
||||||
name="syslog_mark_interval"
|
|
||||||
label="Syslog Mark Interval (seconds, 0=off)"
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.syslog_mark_interval}
|
|
||||||
type="number"
|
|
||||||
onChange={handleValueChange('syslog_mark_interval')}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.trace_raw}
|
|
||||||
onChange={handleValueChange('trace_raw')}
|
|
||||||
value="trace_raw"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Trace EMS telegrams in raw format"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<Typography variant="h6" color="primary" >
|
|
||||||
Analog Input
|
|
||||||
</Typography>
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={data.analog_enabled}
|
|
||||||
onChange={handleValueChange('analog_enabled')}
|
|
||||||
value="analog_enabled"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Enable ADC"
|
|
||||||
/>
|
|
||||||
<br></br>
|
|
||||||
<FormActions>
|
|
||||||
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
|
|
||||||
Save
|
|
||||||
</FormButton>
|
|
||||||
</FormActions>
|
|
||||||
</ValidatorForm>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
417
interface/src/project/EMSESPSettingsForm.tsx
Normal file
417
interface/src/project/EMSESPSettingsForm.tsx
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ValidatorForm, TextValidator, SelectValidator } from 'react-material-ui-form-validator';
|
||||||
|
|
||||||
|
import { Checkbox, Typography, Box, Link, withWidth, WithWidthProps } from '@material-ui/core';
|
||||||
|
import SaveIcon from '@material-ui/icons/Save';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
|
||||||
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
|
||||||
|
import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from "../authentication";
|
||||||
|
|
||||||
|
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel } from '../components';
|
||||||
|
|
||||||
|
import { isIP, optional } from '../validators';
|
||||||
|
|
||||||
|
import { EMSESPSettings } from './EMSESPtypes';
|
||||||
|
|
||||||
|
import { boardProfileSelectItems } from './EMSESPBoardProfiles';
|
||||||
|
|
||||||
|
import { ENDPOINT_ROOT } from "../api";
|
||||||
|
export const BOARD_PROFILE_ENDPOINT = ENDPOINT_ROOT + "boardProfile";
|
||||||
|
|
||||||
|
type EMSESPSettingsFormProps = RestFormProps<EMSESPSettings> & AuthenticatedContextProps & WithWidthProps;
|
||||||
|
|
||||||
|
interface EMSESPSettingsFormState {
|
||||||
|
processing: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||||
|
|
||||||
|
state: EMSESPSettingsFormState = {
|
||||||
|
processing: false
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP));
|
||||||
|
}
|
||||||
|
|
||||||
|
changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const { data, setData } = this.props;
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
board_profile: event.target.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (event.target.value === "CUSTOM")
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.setState({ processing: true });
|
||||||
|
redirectingAuthorizedFetch(BOARD_PROFILE_ENDPOINT, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ code: event.target.value }),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
throw Error("Unexpected response code: " + response.status);
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
this.props.enqueueSnackbar("Profile loaded", { variant: 'success' });
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
led_gpio: json.led_gpio,
|
||||||
|
dallas_gpio: json.dallas_gpio,
|
||||||
|
rx_gpio: json.rx_gpio,
|
||||||
|
tx_gpio: json.tx_gpio,
|
||||||
|
pbutton_gpio: json.pbutton_gpio,
|
||||||
|
board_profile: event.target.value
|
||||||
|
});
|
||||||
|
this.setState({ processing: false });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.enqueueSnackbar(
|
||||||
|
error.message || "Problem fetching board profile",
|
||||||
|
{ variant: "warning" }
|
||||||
|
);
|
||||||
|
this.setState({ processing: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { data, saveData, handleValueChange } = this.props;
|
||||||
|
return (
|
||||||
|
<ValidatorForm onSubmit={saveData}>
|
||||||
|
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
|
||||||
|
<Typography variant="body1">
|
||||||
|
Modify any of the EMS-ESP settings here. For help refer to the <Link target="_blank" href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings" color="primary">{'online documentation'}</Link>.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<br></br>
|
||||||
|
<Typography variant="h6" color="primary" >
|
||||||
|
EMS Bus
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
||||||
|
<Grid item xs={5}>
|
||||||
|
<SelectValidator name="tx_mode"
|
||||||
|
label="Tx Mode"
|
||||||
|
value={data.tx_mode}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={handleValueChange('tx_mode')}
|
||||||
|
margin="normal">
|
||||||
|
<MenuItem value={0}>Off</MenuItem>
|
||||||
|
<MenuItem value={1}>EMS</MenuItem>
|
||||||
|
<MenuItem value={2}>EMS+</MenuItem>
|
||||||
|
<MenuItem value={3}>HT3</MenuItem>
|
||||||
|
<MenuItem value={4}>Hardware</MenuItem>
|
||||||
|
</SelectValidator>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<SelectValidator name="ems_bus_id"
|
||||||
|
label="Bus ID"
|
||||||
|
value={data.ems_bus_id}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={handleValueChange('ems_bus_id')}
|
||||||
|
margin="normal">
|
||||||
|
<MenuItem value={0x0B}>Service Key (0x0B)</MenuItem>
|
||||||
|
<MenuItem value={0x0D}>Modem (0x0D)</MenuItem>
|
||||||
|
<MenuItem value={0x0A}>Terminal (0x0A)</MenuItem>
|
||||||
|
<MenuItem value={0x0F}>Time Module (0x0F)</MenuItem>
|
||||||
|
<MenuItem value={0x12}>Alarm Module (0x12)</MenuItem>
|
||||||
|
</SelectValidator>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:120']}
|
||||||
|
errorMessages={['Tx delay is required', "Must be a number", "Must be 0 or higher", "Max value is 120"]}
|
||||||
|
name="tx_delay"
|
||||||
|
label="Tx start delay (seconds)"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.tx_delay}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('tx_delay')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<br></br>
|
||||||
|
<Typography variant="h6" color="primary" >
|
||||||
|
Board Profile
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box color="warning.main" p={0} mt={0} mb={0}>
|
||||||
|
<Typography variant="body2">
|
||||||
|
<i>Select a pre-configured board layout to automatically set the GPIO pins, or set your own custom configuration</i>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<SelectValidator name="board_profile"
|
||||||
|
label="Board Profile"
|
||||||
|
value={data.board_profile}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.changeBoardProfile}
|
||||||
|
margin="normal">
|
||||||
|
{boardProfileSelectItems()}
|
||||||
|
<MenuItem key={"CUSTOM"} value={"CUSTOM"}>Custom...</MenuItem>
|
||||||
|
</SelectValidator>
|
||||||
|
|
||||||
|
{ (data.board_profile === "CUSTOM") &&
|
||||||
|
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
|
name="rx_gpio"
|
||||||
|
label="Rx GPIO"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.rx_gpio}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('rx_gpio')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
|
name="tx_gpio"
|
||||||
|
label="Tx GPIO"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.tx_gpio}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('tx_gpio')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
|
name="pbutton_gpio"
|
||||||
|
label="Button GPIO"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.pbutton_gpio}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('pbutton_gpio')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
|
name="dallas_gpio"
|
||||||
|
label="Dallas GPIO (0=none)"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.dallas_gpio}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('dallas_gpio')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
|
name="led_gpio"
|
||||||
|
label="LED GPIO (0=none)"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.led_gpio}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('led_gpio')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
|
|
||||||
|
<br></br>
|
||||||
|
<Typography variant="h6" color="primary" >
|
||||||
|
Options
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{ data.dallas_gpio !== 0 &&
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.dallas_parasite}
|
||||||
|
onChange={handleValueChange('dallas_parasite')}
|
||||||
|
value="dallas_parasite"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Enable Dallas parasite mode"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{ data.led_gpio !== 0 &&
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.hide_led}
|
||||||
|
onChange={handleValueChange('hide_led')}
|
||||||
|
value="hide_led"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label = "Hide LED"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
<Grid container spacing={0} direction="row" justify="flex-start" alignItems="flex-start">
|
||||||
|
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.shower_timer}
|
||||||
|
onChange={handleValueChange('shower_timer')}
|
||||||
|
value="shower_timer"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Shower Timer"
|
||||||
|
/>
|
||||||
|
{/* <BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.shower_alert}
|
||||||
|
onChange={handleValueChange('shower_alert')}
|
||||||
|
value="shower_alert"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Shower Alert"
|
||||||
|
/> */}
|
||||||
|
</Grid>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.api_enabled}
|
||||||
|
onChange={handleValueChange('api_enabled')}
|
||||||
|
value="api_enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Enable API write commands"
|
||||||
|
/>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.analog_enabled}
|
||||||
|
onChange={handleValueChange('analog_enabled')}
|
||||||
|
value="analog_enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Enable ADC"
|
||||||
|
/>
|
||||||
|
<br></br>
|
||||||
|
<Typography variant="h6" color="primary" >
|
||||||
|
Syslog
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.syslog_enabled}
|
||||||
|
onChange={handleValueChange('syslog_enabled')}
|
||||||
|
value="syslog_enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Enable Syslog"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{ data.syslog_enabled &&
|
||||||
|
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
||||||
|
<Grid item xs={5}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['isOptionalIP']}
|
||||||
|
errorMessages={["Not a valid IP address"]}
|
||||||
|
name="syslog_host"
|
||||||
|
label="IP"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.syslog_host}
|
||||||
|
onChange={handleValueChange('syslog_host')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
|
||||||
|
errorMessages={['Port is required', "Must be a number", "Must be greater than 0 ", "Max value is 65535"]}
|
||||||
|
name="syslog_port"
|
||||||
|
label="Port"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.syslog_port}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('syslog_port')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={5}>
|
||||||
|
<SelectValidator name="syslog_level"
|
||||||
|
label="Log Level"
|
||||||
|
value={data.syslog_level}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={handleValueChange('syslog_level')}
|
||||||
|
margin="normal">
|
||||||
|
<MenuItem value={-1}>OFF</MenuItem>
|
||||||
|
<MenuItem value={3}>ERR</MenuItem>
|
||||||
|
<MenuItem value={5}>NOTICE</MenuItem>
|
||||||
|
<MenuItem value={6}>INFO</MenuItem>
|
||||||
|
<MenuItem value={7}>DEBUG</MenuItem>
|
||||||
|
<MenuItem value={8}>ALL</MenuItem>
|
||||||
|
</SelectValidator>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
|
||||||
|
errorMessages={['Syslog Mark is required', "Must be a number", "Must be 0 or higher", "Max value is 10"]}
|
||||||
|
name="syslog_mark_interval"
|
||||||
|
label="Mark Interval seconds (0=off)"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.syslog_mark_interval}
|
||||||
|
type="number"
|
||||||
|
onChange={handleValueChange('syslog_mark_interval')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.trace_raw}
|
||||||
|
onChange={handleValueChange('trace_raw')}
|
||||||
|
value="trace_raw"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Output EMS telegrams in raw format"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
|
|
||||||
|
<br></br>
|
||||||
|
<FormActions>
|
||||||
|
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
|
||||||
|
Save
|
||||||
|
</FormButton>
|
||||||
|
</FormActions>
|
||||||
|
</ValidatorForm >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withAuthenticatedContext(withWidth()(EMSESPSettingsForm));
|
||||||
@@ -62,14 +62,14 @@ class EMSESPStatusForm extends Component<EMSESPStatusFormProps> {
|
|||||||
<TableCell>
|
<TableCell>
|
||||||
# Telegrams Received
|
# Telegrams Received
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="right">{formatNumber(data.rx_received)} ({data.rx_quality}%)
|
<TableCell align="right">{formatNumber(data.rx_received)} (quality {data.rx_quality}%)
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell >
|
<TableCell >
|
||||||
# Telegrams Sent
|
# Telegrams Sent
|
||||||
</TableCell >
|
</TableCell >
|
||||||
<TableCell align="right">{formatNumber(data.tx_sent)} ({data.tx_quality}%)
|
<TableCell align="right">{formatNumber(data.tx_sent)} (quality {data.tx_quality}%)
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export interface EMSESPSettings {
|
|||||||
analog_enabled: boolean;
|
analog_enabled: boolean;
|
||||||
pbutton_gpio: number;
|
pbutton_gpio: number;
|
||||||
trace_raw: boolean;
|
trace_raw: boolean;
|
||||||
|
board_profile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum busConnectionStatus {
|
export enum busConnectionStatus {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class SecuritySettingsForm extends React.Component<SecuritySettingsFormProps> {
|
|||||||
/>
|
/>
|
||||||
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
|
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
|
||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
The Super User password is used to sign authentication tokens and also the Console's `su` password. If you modify this all users will be signed out.
|
The Super User password is used to sign authentication tokens and is also the Console's `su` password. If you modify this all users will be signed out.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<FormActions>
|
<FormActions>
|
||||||
|
|||||||
@@ -22,10 +22,8 @@ class UploadFirmwareForm extends React.Component<UploadFirmwareFormProps> {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Box py={2}>
|
<Box py={2}>
|
||||||
Upload a new firmware file (.bin or .bin.gz) below to replace the
|
Upload a new firmware file (.bin or .bin.gz) below to replace the existing firmware.
|
||||||
existing firmware.
|
<p></p>This can take up to a minute. Wait until you see "Activating new Firmware" and EMS-ESP will then automatically restart.
|
||||||
<p></p>This can take up to a minute. Wait until you see "Activating
|
|
||||||
new Firmware" and EMS-ESP will automatically restart.
|
|
||||||
</Box>
|
</Box>
|
||||||
<SingleUpload
|
<SingleUpload
|
||||||
onDrop={this.handleDrop}
|
onDrop={this.handleDrop}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ PButton::PButton() {
|
|||||||
LongPressDelay_ = 750; // Hold period for a long press event (in ms)
|
LongPressDelay_ = 750; // Hold period for a long press event (in ms)
|
||||||
VLongPressDelay_ = 3000; // Hold period for a very long press event (in ms)
|
VLongPressDelay_ = 3000; // Hold period for a very long press event (in ms)
|
||||||
|
|
||||||
cb_onClick = nullptr;
|
cb_onClick = nullptr;
|
||||||
cb_onDblClick = nullptr;
|
cb_onDblClick = nullptr;
|
||||||
cb_onLongPress = nullptr;
|
cb_onLongPress = nullptr;
|
||||||
cb_onVLongPress = nullptr;
|
cb_onVLongPress = nullptr;
|
||||||
|
|
||||||
// Initialization of variables
|
// Initialization of variables
|
||||||
@@ -144,7 +144,7 @@ bool PButton::check(void) {
|
|||||||
|
|
||||||
// added code: raise OnVLongPress event when the button is released, only for pin 0
|
// added code: raise OnVLongPress event when the button is released, only for pin 0
|
||||||
if (state_ == pullMode_ && vLongPressHappened_) {
|
if (state_ == pullMode_ && vLongPressHappened_) {
|
||||||
resultEvent = 4;
|
resultEvent = 4;
|
||||||
vLongPressHappened_ = false;
|
vLongPressHappened_ = false;
|
||||||
longPressHappened_ = false;
|
longPressHappened_ = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,22 +22,20 @@ void APSettingsService::reconfigureAP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::loop() {
|
void APSettingsService::loop() {
|
||||||
// if we have an ETH connection, quit
|
|
||||||
if (emsesp::EMSESP::system_.ethernet_connected()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
unsigned long currentMillis = uuid::get_uptime();
|
unsigned long currentMillis = uuid::get_uptime();
|
||||||
unsigned long manageElapsed = (uint32_t)(currentMillis - _lastManaged);
|
unsigned long manageElapsed = (uint32_t)(currentMillis - _lastManaged);
|
||||||
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
|
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
|
||||||
_lastManaged = currentMillis;
|
_lastManaged = currentMillis;
|
||||||
manageAP();
|
manageAP();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDNS();
|
handleDNS();
|
||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::manageAP() {
|
void APSettingsService::manageAP() {
|
||||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||||
if (_state.provisionMode == AP_MODE_ALWAYS || (_state.provisionMode == AP_MODE_DISCONNECTED && WiFi.status() != WL_CONNECTED)) {
|
bool network_connected = (emsesp::EMSESP::system_.ethernet_connected() || (WiFi.status() == WL_CONNECTED));
|
||||||
|
if (_state.provisionMode == AP_MODE_ALWAYS || (_state.provisionMode == AP_MODE_DISCONNECTED && !network_connected)) {
|
||||||
if (_reconfigureAp || currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) {
|
if (_reconfigureAp || currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) {
|
||||||
startAP();
|
startAP();
|
||||||
}
|
}
|
||||||
@@ -48,13 +46,11 @@ void APSettingsService::manageAP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::startAP() {
|
void APSettingsService::startAP() {
|
||||||
// Serial.println(F("Starting software access point"));
|
|
||||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str());
|
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str());
|
||||||
if (!_dnsServer) {
|
if (!_dnsServer) {
|
||||||
IPAddress apIp = WiFi.softAPIP();
|
IPAddress apIp = WiFi.softAPIP();
|
||||||
// Serial.print(F("Starting captive portal on "));
|
emsesp::EMSESP::logger().info(F("Starting Access Point with captive portal on %s"), apIp.toString().c_str());
|
||||||
// Serial.println(apIp);
|
|
||||||
_dnsServer = new DNSServer;
|
_dnsServer = new DNSServer;
|
||||||
_dnsServer->start(DNS_PORT, "*", apIp);
|
_dnsServer->start(DNS_PORT, "*", apIp);
|
||||||
}
|
}
|
||||||
@@ -62,12 +58,11 @@ void APSettingsService::startAP() {
|
|||||||
|
|
||||||
void APSettingsService::stopAP() {
|
void APSettingsService::stopAP() {
|
||||||
if (_dnsServer) {
|
if (_dnsServer) {
|
||||||
// Serial.println(F("Stopping captive portal"));
|
emsesp::EMSESP::logger().info(F("Stopping Access Point"));
|
||||||
_dnsServer->stop();
|
_dnsServer->stop();
|
||||||
delete _dnsServer;
|
delete _dnsServer;
|
||||||
_dnsServer = nullptr;
|
_dnsServer = nullptr;
|
||||||
}
|
}
|
||||||
// Serial.println(F("Stopping software access point"));
|
|
||||||
WiFi.softAPdisconnect(true);
|
WiFi.softAPdisconnect(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include <APStatus.h>
|
#include <APStatus.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
||||||
: _apSettingsService(apSettingsService) {
|
: _apSettingsService(apSettingsService) {
|
||||||
server->on(AP_STATUS_SERVICE_PATH,
|
server->on(AP_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
HTTP_GET,
|
|
||||||
securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
#ifndef APStatus_h
|
#ifndef APStatus_h
|
||||||
#define APStatus_h
|
#define APStatus_h
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
|
|||||||
@@ -15,14 +15,13 @@ String ArduinoJsonJWT::getSecret() {
|
|||||||
/*
|
/*
|
||||||
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
||||||
*
|
*
|
||||||
* Both come with decent HMAC implmentations supporting sha256, as well as others.
|
* Both come with decent HMAC implementations supporting sha256, as well as others.
|
||||||
*
|
*
|
||||||
* No need to pull in additional crypto libraries - lets use what we already have.
|
* No need to pull in additional crypto libraries - lets use what we already have.
|
||||||
*/
|
*/
|
||||||
String ArduinoJsonJWT::sign(String & payload) {
|
String ArduinoJsonJWT::sign(String & payload) {
|
||||||
unsigned char hmacResult[32];
|
unsigned char hmacResult[32];
|
||||||
{
|
{
|
||||||
#ifdef ESP32
|
|
||||||
mbedtls_md_context_t ctx;
|
mbedtls_md_context_t ctx;
|
||||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||||
mbedtls_md_init(&ctx);
|
mbedtls_md_init(&ctx);
|
||||||
@@ -31,14 +30,6 @@ String ArduinoJsonJWT::sign(String & payload) {
|
|||||||
mbedtls_md_hmac_update(&ctx, (unsigned char *)payload.c_str(), payload.length());
|
mbedtls_md_hmac_update(&ctx, (unsigned char *)payload.c_str(), payload.length());
|
||||||
mbedtls_md_hmac_finish(&ctx, hmacResult);
|
mbedtls_md_hmac_finish(&ctx, hmacResult);
|
||||||
mbedtls_md_free(&ctx);
|
mbedtls_md_free(&ctx);
|
||||||
#elif defined(ESP8266)
|
|
||||||
br_hmac_key_context keyCtx;
|
|
||||||
br_hmac_key_init(&keyCtx, &br_sha256_vtable, _secret.c_str(), _secret.length());
|
|
||||||
br_hmac_context hmacCtx;
|
|
||||||
br_hmac_init(&hmacCtx, &keyCtx, 0);
|
|
||||||
br_hmac_update(&hmacCtx, payload.c_str(), payload.length());
|
|
||||||
br_hmac_out(&hmacCtx, hmacResult);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return encode((char *)hmacResult, 32);
|
return encode((char *)hmacResult, 32);
|
||||||
}
|
}
|
||||||
@@ -94,13 +85,8 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
|
|||||||
String ArduinoJsonJWT::encode(const char * cstr, int inputLen) {
|
String ArduinoJsonJWT::encode(const char * cstr, int inputLen) {
|
||||||
// prepare encoder
|
// prepare encoder
|
||||||
base64_encodestate _state;
|
base64_encodestate _state;
|
||||||
#ifdef ESP32
|
|
||||||
base64_init_encodestate(&_state);
|
base64_init_encodestate(&_state);
|
||||||
size_t encodedLength = base64_encode_expected_len(inputLen) + 1;
|
size_t encodedLength = base64_encode_expected_len(inputLen) + 1;
|
||||||
#elif defined(ESP8266)
|
|
||||||
base64_init_encodestate_nonewlines(&_state);
|
|
||||||
size_t encodedLength = base64_encode_expected_len_nonewlines(inputLen) + 1;
|
|
||||||
#endif
|
|
||||||
// prepare buffer of correct length, returning an empty string on failure
|
// prepare buffer of correct length, returning an empty string on failure
|
||||||
char * buffer = (char *)malloc(encodedLength * sizeof(char));
|
char * buffer = (char *)malloc(encodedLength * sizeof(char));
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
|
|||||||
@@ -5,12 +5,7 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <libb64/cdecode.h>
|
#include <libb64/cdecode.h>
|
||||||
#include <libb64/cencode.h>
|
#include <libb64/cencode.h>
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <mbedtls/md.h>
|
#include <mbedtls/md.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <bearssl/bearssl_hmac.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ArduinoJsonJWT {
|
class ArduinoJsonJWT {
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#include <AuthenticationService.h>
|
#include <AuthenticationService.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
#if FT_ENABLED(FT_SECURITY)
|
#if FT_ENABLED(FT_SECURITY)
|
||||||
|
|
||||||
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _securityManager(securityManager)
|
: _securityManager(securityManager)
|
||||||
, _signInHandler(SIGN_IN_PATH, std::bind(&AuthenticationService::signIn, this, std::placeholders::_1, std::placeholders::_2)) {
|
, _signInHandler(SIGN_IN_PATH, std::bind(&AuthenticationService::signIn, this, _1, _2)) {
|
||||||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1));
|
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, _1));
|
||||||
_signInHandler.setMethod(HTTP_POST);
|
_signInHandler.setMethod(HTTP_POST);
|
||||||
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
|
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
|
||||||
server->addHandler(&_signInHandler);
|
server->addHandler(&_signInHandler);
|
||||||
|
|||||||
@@ -6,11 +6,7 @@
|
|||||||
class ESPUtils {
|
class ESPUtils {
|
||||||
public:
|
public:
|
||||||
static String defaultDeviceValue(String prefix = "") {
|
static String defaultDeviceValue(String prefix = "") {
|
||||||
#ifdef ESP32
|
|
||||||
return prefix + String((uint32_t)ESP.getEfuseMac(), HEX);
|
return prefix + String((uint32_t)ESP.getEfuseMac(), HEX);
|
||||||
#elif defined(ESP8266)
|
|
||||||
return prefix + String(ESP.getChipId(), HEX);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class FSPersistence {
|
|||||||
|
|
||||||
// debug added by Proddy
|
// debug added by Proddy
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
Serial.printf("Read File: %s: ", _filePath);
|
Serial.printf("Reading file: %s: ", _filePath);
|
||||||
serializeJson(jsonDocument, Serial);
|
serializeJson(jsonDocument, Serial);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
#endif
|
#endif
|
||||||
@@ -63,7 +63,7 @@ class FSPersistence {
|
|||||||
|
|
||||||
// debug added by Proddy
|
// debug added by Proddy
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
Serial.printf("Write File: %s: ", _filePath);
|
Serial.printf("Writing to file: %s: ", _filePath);
|
||||||
serializeJson(jsonDocument, Serial);
|
serializeJson(jsonDocument, Serial);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ void FactoryResetService::handleRequest(AsyncWebServerRequest * request) {
|
|||||||
* Delete function assumes that all files are stored flat, within the config directory.
|
* Delete function assumes that all files are stored flat, within the config directory.
|
||||||
*/
|
*/
|
||||||
void FactoryResetService::factoryReset() {
|
void FactoryResetService::factoryReset() {
|
||||||
#ifdef ESP32
|
|
||||||
/*
|
/*
|
||||||
* Based on LITTLEFS. Modified by proddy
|
* Based on LITTLEFS. Modified by proddy
|
||||||
* Could be replaced with fs.rmdir(FS_CONFIG_DIRECTORY) in IDF 4.2
|
* Could be replaced with fs.rmdir(FS_CONFIG_DIRECTORY) in IDF 4.2
|
||||||
@@ -28,14 +27,5 @@ void FactoryResetService::factoryReset() {
|
|||||||
file.close();
|
file.close();
|
||||||
fs->remove(pathStr);
|
fs->remove(pathStr);
|
||||||
}
|
}
|
||||||
#elif defined(ESP8266)
|
|
||||||
Dir configDirectory = fs->openDir(FS_CONFIG_DIRECTORY);
|
|
||||||
while (configDirectory.next()) {
|
|
||||||
String path = FS_CONFIG_DIRECTORY;
|
|
||||||
path.concat("/");
|
|
||||||
path.concat(configDirectory.fileName());
|
|
||||||
fs->remove(path);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
RestartService::restartNow();
|
RestartService::restartNow();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
#ifndef FactoryResetService_h
|
#ifndef FactoryResetService_h
|
||||||
#define FactoryResetService_h
|
#define FactoryResetService_h
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
#include <SecurityManager.h>
|
||||||
#include <RestartService.h>
|
#include <RestartService.h>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#ifndef Features_h
|
#ifndef Features_h
|
||||||
#define Features_h
|
#define Features_h
|
||||||
|
|
||||||
|
// modified by Proddy
|
||||||
|
|
||||||
#define FT_ENABLED(feature) feature
|
#define FT_ENABLED(feature) feature
|
||||||
|
|
||||||
// project feature off by default
|
// project feature on by default
|
||||||
#ifndef FT_PROJECT
|
#ifndef FT_PROJECT
|
||||||
#define FT_PROJECT 0
|
#define FT_PROJECT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// security feature on by default
|
// security feature on by default
|
||||||
@@ -23,14 +25,14 @@
|
|||||||
#define FT_NTP 1
|
#define FT_NTP 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// mqtt feature on by default
|
// ota feature on by default
|
||||||
#ifndef FT_OTA
|
#ifndef FT_OTA
|
||||||
#define FT_OTA 1
|
#define FT_OTA 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// upload firmware feature off by default
|
// upload firmware feature on by default
|
||||||
#ifndef FT_UPLOAD_FIRMWARE
|
#ifndef FT_UPLOAD_FIRMWARE
|
||||||
#define FT_UPLOAD_FIRMWARE 0
|
#define FT_UPLOAD_FIRMWARE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include <FeaturesService.h>
|
#include <FeaturesService.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
FeaturesService::FeaturesService(AsyncWebServer * server) {
|
FeaturesService::FeaturesService(AsyncWebServer * server) {
|
||||||
server->on(FEATURES_SERVICE_PATH, HTTP_GET, std::bind(&FeaturesService::features, this, std::placeholders::_1));
|
server->on(FEATURES_SERVICE_PATH, HTTP_GET, std::bind(&FeaturesService::features, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeaturesService::features(AsyncWebServerRequest * request) {
|
void FeaturesService::features(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -3,14 +3,8 @@
|
|||||||
|
|
||||||
#include <Features.h>
|
#include <Features.h>
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class HttpGetEndpoint {
|
class HttpGetEndpoint {
|
||||||
public:
|
public:
|
||||||
@@ -24,20 +26,14 @@ class HttpGetEndpoint {
|
|||||||
: _stateReader(stateReader)
|
: _stateReader(stateReader)
|
||||||
, _statefulService(statefulService)
|
, _statefulService(statefulService)
|
||||||
, _bufferSize(bufferSize) {
|
, _bufferSize(bufferSize) {
|
||||||
server->on(servicePath.c_str(),
|
server->on(servicePath.c_str(), HTTP_GET, securityManager->wrapRequest(std::bind(&HttpGetEndpoint::fetchSettings, this, _1), authenticationPredicate));
|
||||||
HTTP_GET,
|
|
||||||
securityManager->wrapRequest(std::bind(&HttpGetEndpoint::fetchSettings, this, std::placeholders::_1), authenticationPredicate));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpGetEndpoint(JsonStateReader<T> stateReader,
|
HttpGetEndpoint(JsonStateReader<T> stateReader, StatefulService<T> * statefulService, AsyncWebServer * server, const String & servicePath, size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncWebServer * server,
|
|
||||||
const String & servicePath,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: _stateReader(stateReader)
|
: _stateReader(stateReader)
|
||||||
, _statefulService(statefulService)
|
, _statefulService(statefulService)
|
||||||
, _bufferSize(bufferSize) {
|
, _bufferSize(bufferSize) {
|
||||||
server->on(servicePath.c_str(), HTTP_GET, std::bind(&HttpGetEndpoint::fetchSettings, this, std::placeholders::_1));
|
server->on(servicePath.c_str(), HTTP_GET, std::bind(&HttpGetEndpoint::fetchSettings, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -69,25 +65,17 @@ class HttpPostEndpoint {
|
|||||||
: _stateReader(stateReader)
|
: _stateReader(stateReader)
|
||||||
, _stateUpdater(stateUpdater)
|
, _stateUpdater(stateUpdater)
|
||||||
, _statefulService(statefulService)
|
, _statefulService(statefulService)
|
||||||
, _updateHandler(servicePath,
|
, _updateHandler(servicePath, securityManager->wrapCallback(std::bind(&HttpPostEndpoint::updateSettings, this, _1, _2), authenticationPredicate), bufferSize)
|
||||||
securityManager->wrapCallback(std::bind(&HttpPostEndpoint::updateSettings, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
authenticationPredicate),
|
|
||||||
bufferSize)
|
|
||||||
, _bufferSize(bufferSize) {
|
, _bufferSize(bufferSize) {
|
||||||
_updateHandler.setMethod(HTTP_POST);
|
_updateHandler.setMethod(HTTP_POST);
|
||||||
server->addHandler(&_updateHandler);
|
server->addHandler(&_updateHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpPostEndpoint(JsonStateReader<T> stateReader,
|
HttpPostEndpoint(JsonStateReader<T> stateReader, JsonStateUpdater<T> stateUpdater, StatefulService<T> * statefulService, AsyncWebServer * server, const String & servicePath, size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
JsonStateUpdater<T> stateUpdater,
|
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncWebServer * server,
|
|
||||||
const String & servicePath,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: _stateReader(stateReader)
|
: _stateReader(stateReader)
|
||||||
, _stateUpdater(stateUpdater)
|
, _stateUpdater(stateUpdater)
|
||||||
, _statefulService(statefulService)
|
, _statefulService(statefulService)
|
||||||
, _updateHandler(servicePath, std::bind(&HttpPostEndpoint::updateSettings, this, std::placeholders::_1, std::placeholders::_2), bufferSize)
|
, _updateHandler(servicePath, std::bind(&HttpPostEndpoint::updateSettings, this, _1, _2), bufferSize)
|
||||||
, _bufferSize(bufferSize) {
|
, _bufferSize(bufferSize) {
|
||||||
_updateHandler.setMethod(HTTP_POST);
|
_updateHandler.setMethod(HTTP_POST);
|
||||||
server->addHandler(&_updateHandler);
|
server->addHandler(&_updateHandler);
|
||||||
@@ -137,12 +125,7 @@ class HttpEndpoint : public HttpGetEndpoint<T>, public HttpPostEndpoint<T> {
|
|||||||
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize) {
|
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpEndpoint(JsonStateReader<T> stateReader,
|
HttpEndpoint(JsonStateReader<T> stateReader, JsonStateUpdater<T> stateUpdater, StatefulService<T> * statefulService, AsyncWebServer * server, const String & servicePath, size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
JsonStateUpdater<T> stateUpdater,
|
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncWebServer * server,
|
|
||||||
const String & servicePath,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, bufferSize)
|
: HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, bufferSize)
|
||||||
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) {
|
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <StatefulService.h>
|
#include <StatefulService.h>
|
||||||
#include <AsyncMqttClient.h>
|
#include <AsyncMqttClient.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
#define MQTT_ORIGIN_ID "mqtt"
|
#define MQTT_ORIGIN_ID "mqtt"
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -31,11 +33,7 @@ class MqttConnector {
|
|||||||
template <class T>
|
template <class T>
|
||||||
class MqttPub : virtual public MqttConnector<T> {
|
class MqttPub : virtual public MqttConnector<T> {
|
||||||
public:
|
public:
|
||||||
MqttPub(JsonStateReader<T> stateReader,
|
MqttPub(JsonStateReader<T> stateReader, StatefulService<T> * statefulService, AsyncMqttClient * mqttClient, const String & pubTopic = "", size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncMqttClient * mqttClient,
|
|
||||||
const String & pubTopic = "",
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: MqttConnector<T>(statefulService, mqttClient, bufferSize)
|
: MqttConnector<T>(statefulService, mqttClient, bufferSize)
|
||||||
, _stateReader(stateReader)
|
, _stateReader(stateReader)
|
||||||
, _pubTopic(pubTopic) {
|
, _pubTopic(pubTopic) {
|
||||||
@@ -76,22 +74,11 @@ class MqttPub : virtual public MqttConnector<T> {
|
|||||||
template <class T>
|
template <class T>
|
||||||
class MqttSub : virtual public MqttConnector<T> {
|
class MqttSub : virtual public MqttConnector<T> {
|
||||||
public:
|
public:
|
||||||
MqttSub(JsonStateUpdater<T> stateUpdater,
|
MqttSub(JsonStateUpdater<T> stateUpdater, StatefulService<T> * statefulService, AsyncMqttClient * mqttClient, const String & subTopic = "", size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncMqttClient * mqttClient,
|
|
||||||
const String & subTopic = "",
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: MqttConnector<T>(statefulService, mqttClient, bufferSize)
|
: MqttConnector<T>(statefulService, mqttClient, bufferSize)
|
||||||
, _stateUpdater(stateUpdater)
|
, _stateUpdater(stateUpdater)
|
||||||
, _subTopic(subTopic) {
|
, _subTopic(subTopic) {
|
||||||
MqttConnector<T>::_mqttClient->onMessage(std::bind(&MqttSub::onMqttMessage,
|
MqttConnector<T>::_mqttClient->onMessage(std::bind(&MqttSub::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||||
this,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::placeholders::_2,
|
|
||||||
std::placeholders::_3,
|
|
||||||
std::placeholders::_4,
|
|
||||||
std::placeholders::_5,
|
|
||||||
std::placeholders::_6));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSubTopic(const String & subTopic) {
|
void setSubTopic(const String & subTopic) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
||||||
*
|
*
|
||||||
@@ -33,10 +35,9 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
|
|||||||
, _disconnectedAt(0)
|
, _disconnectedAt(0)
|
||||||
, _disconnectReason(AsyncMqttClientDisconnectReason::TCP_DISCONNECTED)
|
, _disconnectReason(AsyncMqttClientDisconnectReason::TCP_DISCONNECTED)
|
||||||
, _mqttClient() {
|
, _mqttClient() {
|
||||||
WiFi.onEvent(std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
WiFi.onEvent(std::bind(&MqttSettingsService::WiFiEvent, this, _1, _2));
|
||||||
WiFi.onEvent(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
|
_mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
||||||
_mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, std::placeholders::_1));
|
_mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
||||||
_mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, std::placeholders::_1));
|
|
||||||
addUpdateHandler([&](const String & originId) { onConfigUpdated(); }, false);
|
addUpdateHandler([&](const String & originId) { onConfigUpdated(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,17 +80,11 @@ AsyncMqttClient * MqttSettingsService::getMqttClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
||||||
// Serial.print(F("Connected to MQTT, "));
|
// emsesp::EMSESP::logger().info(F("Connected to MQTT, %s"), (sessionPresent) ? F("with persistent session") : F("without persistent session"));
|
||||||
// if (sessionPresent) {
|
|
||||||
// Serial.println(F("with persistent session"));
|
|
||||||
// } else {
|
|
||||||
// Serial.println(F("without persistent session"));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||||
// Serial.print(F("Disconnected from MQTT reason: "));
|
// emsesp::EMSESP::logger().info(F("Disconnected from MQTT reason: %s"), (uint8_t)reason);
|
||||||
// Serial.println((uint8_t)reason);
|
|
||||||
_disconnectReason = reason;
|
_disconnectReason = reason;
|
||||||
_disconnectedAt = uuid::get_uptime();
|
_disconnectedAt = uuid::get_uptime();
|
||||||
}
|
}
|
||||||
@@ -99,47 +94,38 @@ void MqttSettingsService::onConfigUpdated() {
|
|||||||
_disconnectedAt = 0;
|
_disconnectedAt = 0;
|
||||||
|
|
||||||
// added by proddy
|
// added by proddy
|
||||||
// reload EMS-ESP MQTT settings
|
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
||||||
emsesp::EMSESP::mqtt_.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
void MqttSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
switch (event) {
|
||||||
if (_state.enabled) {
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
// Serial.println(F("WiFi connection dropped, starting MQTT client."));
|
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||||
onConfigUpdated();
|
if (_state.enabled) {
|
||||||
}
|
// emsesp::EMSESP::logger().info(F("Network connection found, starting MQTT client"));
|
||||||
}
|
onConfigUpdated();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
void MqttSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||||
if (_state.enabled) {
|
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||||
// Serial.println(F("WiFi connection dropped, stopping MQTT client."));
|
if (_state.enabled) {
|
||||||
onConfigUpdated();
|
// emsesp::EMSESP::logger().info(F("Network connection dropped, stopping MQTT client"));
|
||||||
}
|
onConfigUpdated();
|
||||||
}
|
}
|
||||||
#elif defined(ESP8266)
|
break;
|
||||||
void MqttSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP & event) {
|
|
||||||
if (_state.enabled) {
|
|
||||||
// Serial.println(F("WiFi connection dropped, starting MQTT client."));
|
|
||||||
onConfigUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected & event) {
|
default:
|
||||||
if (_state.enabled) {
|
break;
|
||||||
// Serial.println(F("WiFi connection dropped, stopping MQTT client."));
|
|
||||||
onConfigUpdated();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void MqttSettingsService::configureMqtt() {
|
void MqttSettingsService::configureMqtt() {
|
||||||
// disconnect if currently connected
|
// disconnect if currently connected
|
||||||
_mqttClient.disconnect();
|
_mqttClient.disconnect();
|
||||||
|
|
||||||
// only connect if WiFi is connected and MQTT is enabled
|
// only connect if WiFi is connected and MQTT is enabled
|
||||||
if (_state.enabled && WiFi.isConnected()) {
|
if (_state.enabled && emsesp::EMSESP::system_.network_connected()) {
|
||||||
// Serial.println(F("Connecting to MQTT..."));
|
|
||||||
_mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
|
_mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
|
||||||
if (_state.username.length() > 0) {
|
if (_state.username.length() > 0) {
|
||||||
_mqttClient.setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername), retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
_mqttClient.setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername), retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
||||||
@@ -153,7 +139,7 @@ void MqttSettingsService::configureMqtt() {
|
|||||||
_mqttClient.connect();
|
_mqttClient.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
emsesp::EMSESP::dallassensor_.reload();
|
emsesp::EMSESP::dallassensor_.reload(); // added by Proddy for EMS-ESP
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
||||||
@@ -182,6 +168,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
|||||||
root["ha_climate_format"] = settings.ha_climate_format;
|
root["ha_climate_format"] = settings.ha_climate_format;
|
||||||
root["ha_enabled"] = settings.ha_enabled;
|
root["ha_enabled"] = settings.ha_enabled;
|
||||||
root["nested_format"] = settings.nested_format;
|
root["nested_format"] = settings.nested_format;
|
||||||
|
root["subscribe_format"] = settings.subscribe_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) {
|
StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) {
|
||||||
@@ -213,6 +200,7 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
|||||||
newSettings.ha_climate_format = root["ha_climate_format"] | EMSESP_DEFAULT_HA_CLIMATE_FORMAT;
|
newSettings.ha_climate_format = root["ha_climate_format"] | EMSESP_DEFAULT_HA_CLIMATE_FORMAT;
|
||||||
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
|
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
|
||||||
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
|
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
|
||||||
|
newSettings.subscribe_format = root["subscribe_format"] | EMSESP_DEFAULT_SUBSCRIBE_FORMAT;
|
||||||
|
|
||||||
if (newSettings.mqtt_qos != settings.mqtt_qos) {
|
if (newSettings.mqtt_qos != settings.mqtt_qos) {
|
||||||
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
|
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
|
||||||
@@ -228,6 +216,10 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
|||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newSettings.subscribe_format != settings.subscribe_format) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (newSettings.ha_climate_format != settings.ha_climate_format) {
|
if (newSettings.ha_climate_format != settings.ha_climate_format) {
|
||||||
emsesp::EMSESP::mqtt_.ha_climate_format(newSettings.ha_climate_format);
|
emsesp::EMSESP::mqtt_.ha_climate_format(newSettings.ha_climate_format);
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|||||||
@@ -41,11 +41,7 @@
|
|||||||
#ifndef FACTORY_MQTT_CLIENT_ID
|
#ifndef FACTORY_MQTT_CLIENT_ID
|
||||||
#define FACTORY_MQTT_CLIENT_ID generateClientId()
|
#define FACTORY_MQTT_CLIENT_ID generateClientId()
|
||||||
static String generateClientId() {
|
static String generateClientId() {
|
||||||
#ifdef ESP32
|
|
||||||
return ESPUtils::defaultDeviceValue("esp32-");
|
return ESPUtils::defaultDeviceValue("esp32-");
|
||||||
#elif defined(ESP8266)
|
|
||||||
return ESPUtils::defaultDeviceValue("esp8266-");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -69,6 +65,9 @@ static String generateClientId() {
|
|||||||
#define EMSESP_DEFAULT_HA_ENABLED false
|
#define EMSESP_DEFAULT_HA_ENABLED false
|
||||||
#define EMSESP_DEFAULT_PUBLISH_TIME 10
|
#define EMSESP_DEFAULT_PUBLISH_TIME 10
|
||||||
#define EMSESP_DEFAULT_NESTED_FORMAT true
|
#define EMSESP_DEFAULT_NESTED_FORMAT true
|
||||||
|
#define EMSESP_DEFAULT_SUBSCRIBE_FORMAT 0
|
||||||
|
|
||||||
|
#define EMSESP_DEFAULT_BOARD_PROFILE "S32"
|
||||||
|
|
||||||
class MqttSettings {
|
class MqttSettings {
|
||||||
public:
|
public:
|
||||||
@@ -76,7 +75,6 @@ class MqttSettings {
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
String host;
|
String host;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
String base;
|
|
||||||
|
|
||||||
// username and password
|
// username and password
|
||||||
String username;
|
String username;
|
||||||
@@ -91,6 +89,7 @@ class MqttSettings {
|
|||||||
uint16_t maxTopicLength;
|
uint16_t maxTopicLength;
|
||||||
|
|
||||||
// proddy EMS-ESP specific
|
// proddy EMS-ESP specific
|
||||||
|
String base;
|
||||||
uint16_t publish_time_boiler;
|
uint16_t publish_time_boiler;
|
||||||
uint16_t publish_time_thermostat;
|
uint16_t publish_time_thermostat;
|
||||||
uint16_t publish_time_solar;
|
uint16_t publish_time_solar;
|
||||||
@@ -104,6 +103,7 @@ class MqttSettings {
|
|||||||
uint8_t ha_climate_format;
|
uint8_t ha_climate_format;
|
||||||
bool ha_enabled;
|
bool ha_enabled;
|
||||||
bool nested_format;
|
bool nested_format;
|
||||||
|
uint8_t subscribe_format;
|
||||||
|
|
||||||
static void read(MqttSettings & settings, JsonObject & root);
|
static void read(MqttSettings & settings, JsonObject & root);
|
||||||
static StateUpdateResult update(JsonObject & root, MqttSettings & settings);
|
static StateUpdateResult update(JsonObject & root, MqttSettings & settings);
|
||||||
@@ -146,8 +146,7 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
|||||||
// the MQTT client instance
|
// the MQTT client instance
|
||||||
AsyncMqttClient _mqttClient;
|
AsyncMqttClient _mqttClient;
|
||||||
|
|
||||||
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
||||||
void configureMqtt();
|
void configureMqtt();
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
||||||
: _mqttSettingsService(mqttSettingsService) {
|
: _mqttSettingsService(mqttSettingsService) {
|
||||||
server->on(MQTT_STATUS_SERVICE_PATH,
|
server->on(MQTT_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&MqttStatus::mqttStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest(std::bind(&MqttStatus::mqttStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
#ifndef MqttStatus_h
|
#ifndef MqttStatus_h
|
||||||
#define MqttStatus_h
|
#define MqttStatus_h
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <MqttSettingsService.h>
|
#include <MqttSettingsService.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#include <NTPSettingsService.h>
|
#include <NTPSettingsService.h>
|
||||||
|
|
||||||
|
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
||||||
, _timeHandler(TIME_PATH, securityManager->wrapCallback(std::bind(&NTPSettingsService::configureTime, this, std::placeholders::_1, std::placeholders::_2), AuthenticationPredicates::IS_ADMIN)) {
|
, _timeHandler(TIME_PATH, securityManager->wrapCallback(std::bind(&NTPSettingsService::configureTime, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
|
||||||
_timeHandler.setMethod(HTTP_POST);
|
_timeHandler.setMethod(HTTP_POST);
|
||||||
_timeHandler.setMaxContentLength(MAX_TIME_SIZE);
|
_timeHandler.setMaxContentLength(MAX_TIME_SIZE);
|
||||||
server->addHandler(&_timeHandler);
|
server->addHandler(&_timeHandler);
|
||||||
|
|
||||||
WiFi.onEvent(std::bind(&NTPSettingsService::WiFiEvent, this, std::placeholders::_1));
|
WiFi.onEvent(std::bind(&NTPSettingsService::WiFiEvent, this, _1));
|
||||||
|
|
||||||
addUpdateHandler([&](const String & originId) { configureNTP(); }, false);
|
addUpdateHandler([&](const String & originId) { configureNTP(); }, false);
|
||||||
}
|
}
|
||||||
@@ -22,14 +26,15 @@ void NTPSettingsService::begin() {
|
|||||||
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||||
// Serial.println(F("WiFi connection dropped, stopping NTP."));
|
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||||
|
emsesp::EMSESP::logger().info(F("WiFi connection dropped, stopping NTP"));
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
configureNTP();
|
configureNTP();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYSTEM_EVENT_STA_GOT_IP:
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||||
// Serial.println(F("Got IP address, starting NTP Synchronization"));
|
// emsesp::EMSESP::logger().info(F("Got IP address, starting NTP synchronization"));
|
||||||
connected_ = true;
|
connected_ = true;
|
||||||
configureNTP();
|
configureNTP();
|
||||||
break;
|
break;
|
||||||
@@ -41,7 +46,7 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
|||||||
|
|
||||||
void NTPSettingsService::configureNTP() {
|
void NTPSettingsService::configureNTP() {
|
||||||
if (connected_ && _state.enabled) {
|
if (connected_ && _state.enabled) {
|
||||||
// Serial.println(F("Starting NTP..."));
|
emsesp::EMSESP::logger().info(F("Starting NTP"));
|
||||||
configTzTime(_state.tzFormat.c_str(), _state.server.c_str());
|
configTzTime(_state.tzFormat.c_str(), _state.server.c_str());
|
||||||
} else {
|
} else {
|
||||||
setenv("TZ", _state.tzFormat.c_str(), 1);
|
setenv("TZ", _state.tzFormat.c_str(), 1);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include <NTPStatus.h>
|
#include <NTPStatus.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED));
|
server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -2,15 +2,10 @@
|
|||||||
#define NTPStatus_h
|
#define NTPStatus_h
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <lwip/apps/sntp.h>
|
#include <lwip/apps/sntp.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#include <sntp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include <NetworkSettingsService.h>
|
#include <NetworkSettingsService.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(NetworkSettings::read, NetworkSettings::update, this, server, NETWORK_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(NetworkSettings::read, NetworkSettings::update, this, server, NETWORK_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE)
|
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE)
|
||||||
@@ -17,7 +19,7 @@ NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs,
|
|||||||
WiFi.mode(WIFI_MODE_MAX);
|
WiFi.mode(WIFI_MODE_MAX);
|
||||||
WiFi.mode(WIFI_MODE_NULL);
|
WiFi.mode(WIFI_MODE_NULL);
|
||||||
|
|
||||||
WiFi.onEvent(std::bind(&NetworkSettingsService::WiFiEvent, this, std::placeholders::_1));
|
WiFi.onEvent(std::bind(&NetworkSettingsService::WiFiEvent, this, _1));
|
||||||
|
|
||||||
addUpdateHandler([&](const String & originId) { reconfigureWiFiConnection(); }, false);
|
addUpdateHandler([&](const String & originId) { reconfigureWiFiConnection(); }, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ class NetworkSettings {
|
|||||||
String password;
|
String password;
|
||||||
String hostname;
|
String hostname;
|
||||||
bool staticIPConfig;
|
bool staticIPConfig;
|
||||||
uint8_t ethernet_profile;
|
|
||||||
|
|
||||||
// optional configuration for static IP address
|
// optional configuration for static IP address
|
||||||
IPAddress localIP;
|
IPAddress localIP;
|
||||||
@@ -46,7 +45,6 @@ class NetworkSettings {
|
|||||||
root["password"] = settings.password;
|
root["password"] = settings.password;
|
||||||
root["hostname"] = settings.hostname;
|
root["hostname"] = settings.hostname;
|
||||||
root["static_ip_config"] = settings.staticIPConfig;
|
root["static_ip_config"] = settings.staticIPConfig;
|
||||||
root["ethernet_profile"] = settings.ethernet_profile;
|
|
||||||
|
|
||||||
// extended settings
|
// extended settings
|
||||||
JsonUtils::writeIP(root, "local_ip", settings.localIP);
|
JsonUtils::writeIP(root, "local_ip", settings.localIP);
|
||||||
@@ -61,7 +59,6 @@ class NetworkSettings {
|
|||||||
settings.password = root["password"] | FACTORY_WIFI_PASSWORD;
|
settings.password = root["password"] | FACTORY_WIFI_PASSWORD;
|
||||||
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
|
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
|
||||||
settings.staticIPConfig = root["static_ip_config"] | false;
|
settings.staticIPConfig = root["static_ip_config"] | false;
|
||||||
settings.ethernet_profile = root["ethernet_profile"] | 0; // no ethernet
|
|
||||||
|
|
||||||
// extended settings
|
// extended settings
|
||||||
JsonUtils::readIP(root, "local_ip", settings.localIP);
|
JsonUtils::readIP(root, "local_ip", settings.localIP);
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
NetworkStatus::NetworkStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
NetworkStatus::NetworkStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(NETWORK_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&NetworkStatus::networkStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED));
|
server->on(NETWORK_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&NetworkStatus::networkStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -2,15 +2,13 @@
|
|||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
OTASettingsService::OTASettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
OTASettingsService::OTASettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(OTASettings::read, OTASettings::update, this, server, OTA_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(OTASettings::read, OTASettings::update, this, server, OTA_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(OTASettings::read, OTASettings::update, this, fs, OTA_SETTINGS_FILE)
|
, _fsPersistence(OTASettings::read, OTASettings::update, this, fs, OTA_SETTINGS_FILE)
|
||||||
, _arduinoOTA(nullptr) {
|
, _arduinoOTA(nullptr) {
|
||||||
#ifdef ESP32
|
WiFi.onEvent(std::bind(&OTASettingsService::WiFiEvent, this, _1, _2));
|
||||||
WiFi.onEvent(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
_onStationModeGotIPHandler = WiFi.onStationModeGotIP(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1));
|
|
||||||
#endif
|
|
||||||
addUpdateHandler([&](const String & originId) { configureArduinoOTA(); }, false);
|
addUpdateHandler([&](const String & originId) { configureArduinoOTA(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,54 +25,51 @@ void OTASettingsService::loop() {
|
|||||||
|
|
||||||
void OTASettingsService::configureArduinoOTA() {
|
void OTASettingsService::configureArduinoOTA() {
|
||||||
if (_arduinoOTA) {
|
if (_arduinoOTA) {
|
||||||
#ifdef ESP32
|
|
||||||
_arduinoOTA->end();
|
_arduinoOTA->end();
|
||||||
#endif
|
|
||||||
delete _arduinoOTA;
|
delete _arduinoOTA;
|
||||||
_arduinoOTA = nullptr;
|
_arduinoOTA = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_state.enabled) {
|
if (_state.enabled) {
|
||||||
// Serial.println(F("Starting OTA Update Service..."));
|
|
||||||
_arduinoOTA = new ArduinoOTAClass;
|
_arduinoOTA = new ArduinoOTAClass;
|
||||||
_arduinoOTA->setPort(_state.port);
|
_arduinoOTA->setPort(_state.port);
|
||||||
_arduinoOTA->setPassword(_state.password.c_str());
|
_arduinoOTA->setPassword(_state.password.c_str());
|
||||||
|
|
||||||
_arduinoOTA->onStart([]() {
|
_arduinoOTA->onStart([]() {
|
||||||
// Serial.println(F("Starting"));
|
Serial.println(F("Starting"));
|
||||||
emsesp::EMSESP::system_.upload_status(true);
|
emsesp::EMSESP::system_.upload_status(true);
|
||||||
});
|
});
|
||||||
_arduinoOTA->onEnd([]() {
|
_arduinoOTA->onEnd([]() {
|
||||||
// Serial.println(F("\r\nEnd"));
|
Serial.println(F("\r\nEnd"));
|
||||||
emsesp::EMSESP::system_.upload_status(false);
|
emsesp::EMSESP::system_.upload_status(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// _arduinoOTA->onProgress([](unsigned int progress, unsigned int total) {
|
_arduinoOTA->onProgress([](unsigned int progress, unsigned int total) { Serial.printf_P(PSTR("Progress: %u%%\r\n"), (progress / (total / 100))); });
|
||||||
// Serial.printf_P(PSTR("Progress: %u%%\r\n"), (progress / (total / 100)));
|
_arduinoOTA->onError([](ota_error_t error) {
|
||||||
// });
|
Serial.printf("Error[%u]: ", error);
|
||||||
// _arduinoOTA->onError([](ota_error_t error) {
|
if (error == OTA_AUTH_ERROR)
|
||||||
// Serial.printf("Error[%u]: ", error);
|
Serial.println(F("Auth Failed"));
|
||||||
// if (error == OTA_AUTH_ERROR)
|
else if (error == OTA_BEGIN_ERROR)
|
||||||
// Serial.println(F("Auth Failed"));
|
Serial.println(F("Begin Failed"));
|
||||||
// else if (error == OTA_BEGIN_ERROR)
|
else if (error == OTA_CONNECT_ERROR)
|
||||||
// Serial.println(F("Begin Failed"));
|
Serial.println(F("Connect Failed"));
|
||||||
// else if (error == OTA_CONNECT_ERROR)
|
else if (error == OTA_RECEIVE_ERROR)
|
||||||
// Serial.println(F("Connect Failed"));
|
Serial.println(F("Receive Failed"));
|
||||||
// else if (error == OTA_RECEIVE_ERROR)
|
else if (error == OTA_END_ERROR)
|
||||||
// Serial.println(F("Receive Failed"));
|
Serial.println(F("End Failed"));
|
||||||
// else if (error == OTA_END_ERROR)
|
});
|
||||||
// Serial.println(F("End Failed"));
|
|
||||||
// });
|
|
||||||
|
|
||||||
_arduinoOTA->begin();
|
_arduinoOTA->begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
void OTASettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
void OTASettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
switch (event) {
|
||||||
configureArduinoOTA();
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
|
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||||
|
configureArduinoOTA();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#elif defined(ESP8266)
|
|
||||||
void OTASettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP & event) {
|
|
||||||
configureArduinoOTA();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -4,11 +4,7 @@
|
|||||||
#include <HttpEndpoint.h>
|
#include <HttpEndpoint.h>
|
||||||
#include <FSPersistence.h>
|
#include <FSPersistence.h>
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266mDNS.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
@@ -61,12 +57,7 @@ class OTASettingsService : public StatefulService<OTASettings> {
|
|||||||
ArduinoOTAClass * _arduinoOTA;
|
ArduinoOTAClass * _arduinoOTA;
|
||||||
|
|
||||||
void configureArduinoOTA();
|
void configureArduinoOTA();
|
||||||
#ifdef ESP32
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
WiFiEventHandler _onStationModeGotIPHandler;
|
|
||||||
void onStationModeGotIP(const WiFiEventStationModeGotIP & event);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // end OTASettingsService_h
|
#endif // end OTASettingsService_h
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#include <RestartService.h>
|
#include <RestartService.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
RestartService::RestartService(AsyncWebServer * server, SecurityManager * securityManager) {
|
RestartService::RestartService(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(RESTART_SERVICE_PATH,
|
server->on(RESTART_SERVICE_PATH, HTTP_POST, securityManager->wrapRequest(std::bind(&RestartService::restart, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||||
HTTP_POST,
|
|
||||||
securityManager->wrapRequest(std::bind(&RestartService::restart, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestartService::restart(AsyncWebServerRequest * request) {
|
void RestartService::restart(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
#ifndef RestartService_h
|
#ifndef RestartService_h
|
||||||
#define RestartService_h
|
#define RestartService_h
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
#include <SecurityManager.h>
|
||||||
|
|||||||
@@ -6,10 +6,8 @@
|
|||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#ifdef ESP32
|
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/semphr.h>
|
#include <freertos/semphr.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEFAULT_BUFFER_SIZE
|
#ifndef DEFAULT_BUFFER_SIZE
|
||||||
#define DEFAULT_BUFFER_SIZE 1024
|
#define DEFAULT_BUFFER_SIZE 1024
|
||||||
@@ -45,16 +43,10 @@ template <class T>
|
|||||||
class StatefulService {
|
class StatefulService {
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
#ifdef ESP32
|
|
||||||
StatefulService(Args &&... args)
|
StatefulService(Args &&... args)
|
||||||
: _state(std::forward<Args>(args)...)
|
: _state(std::forward<Args>(args)...)
|
||||||
, _accessMutex(xSemaphoreCreateRecursiveMutex()) {
|
, _accessMutex(xSemaphoreCreateRecursiveMutex()) {
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
StatefulService(Args &&... args)
|
|
||||||
: _state(std::forward<Args>(args)...) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
update_handler_id_t addUpdateHandler(StateUpdateCallback cb, bool allowRemove = true) {
|
update_handler_id_t addUpdateHandler(StateUpdateCallback cb, bool allowRemove = true) {
|
||||||
if (!cb) {
|
if (!cb) {
|
||||||
@@ -131,21 +123,15 @@ class StatefulService {
|
|||||||
T _state;
|
T _state;
|
||||||
|
|
||||||
inline void beginTransaction() {
|
inline void beginTransaction() {
|
||||||
#ifdef ESP32
|
|
||||||
xSemaphoreTakeRecursive(_accessMutex, portMAX_DELAY);
|
xSemaphoreTakeRecursive(_accessMutex, portMAX_DELAY);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void endTransaction() {
|
inline void endTransaction() {
|
||||||
#ifdef ESP32
|
|
||||||
xSemaphoreGiveRecursive(_accessMutex);
|
xSemaphoreGiveRecursive(_accessMutex);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef ESP32
|
SemaphoreHandle_t _accessMutex;
|
||||||
SemaphoreHandle_t _accessMutex;
|
|
||||||
#endif
|
|
||||||
std::list<StateUpdateHandlerInfo_t> _updateHandlers;
|
std::list<StateUpdateHandlerInfo_t> _updateHandlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#include <SystemStatus.h>
|
#include <SystemStatus.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED));
|
server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE);
|
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
root["esp_platform"] = "esp32";
|
root["esp_platform"] = "ESP32";
|
||||||
root["max_alloc_heap"] = ESP.getMaxAllocHeap();
|
root["max_alloc_heap"] = ESP.getMaxAllocHeap();
|
||||||
root["psram_size"] = ESP.getPsramSize();
|
root["psram_size"] = ESP.getPsramSize();
|
||||||
root["free_psram"] = ESP.getFreePsram();
|
root["free_psram"] = ESP.getFreePsram();
|
||||||
|
|||||||
@@ -1,21 +1,10 @@
|
|||||||
#include <UploadFirmwareService.h>
|
#include <UploadFirmwareService.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
UploadFirmwareService::UploadFirmwareService(AsyncWebServer * server, SecurityManager * securityManager)
|
UploadFirmwareService::UploadFirmwareService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _securityManager(securityManager) {
|
: _securityManager(securityManager) {
|
||||||
server->on(UPLOAD_FIRMWARE_PATH,
|
server->on(UPLOAD_FIRMWARE_PATH, HTTP_POST, std::bind(&UploadFirmwareService::uploadComplete, this, _1), std::bind(&UploadFirmwareService::handleUpload, this, _1, _2, _3, _4, _5, _6));
|
||||||
HTTP_POST,
|
|
||||||
std::bind(&UploadFirmwareService::uploadComplete, this, std::placeholders::_1),
|
|
||||||
std::bind(&UploadFirmwareService::handleUpload,
|
|
||||||
this,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::placeholders::_2,
|
|
||||||
std::placeholders::_3,
|
|
||||||
std::placeholders::_4,
|
|
||||||
std::placeholders::_5,
|
|
||||||
std::placeholders::_6));
|
|
||||||
#ifdef ESP8266
|
|
||||||
Update.runAsync(true);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UploadFirmwareService::handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
void UploadFirmwareService::handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
||||||
@@ -72,9 +61,5 @@ void UploadFirmwareService::handleError(AsyncWebServerRequest * request, int cod
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UploadFirmwareService::handleEarlyDisconnect() {
|
void UploadFirmwareService::handleEarlyDisconnect() {
|
||||||
#ifdef ESP32
|
|
||||||
Update.abort();
|
Update.abort();
|
||||||
#elif defined(ESP8266)
|
|
||||||
Update.end();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,9 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
#include <SecurityManager.h>
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#define WEB_SOCKET_ORIGIN "websocket"
|
#define WEB_SOCKET_ORIGIN "websocket"
|
||||||
#define WEB_SOCKET_ORIGIN_CLIENT_ID_PREFIX "websocket:"
|
#define WEB_SOCKET_ORIGIN_CLIENT_ID_PREFIX "websocket:"
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class WebSocketConnector {
|
class WebSocketConnector {
|
||||||
protected:
|
protected:
|
||||||
@@ -18,27 +20,15 @@ class WebSocketConnector {
|
|||||||
AsyncWebSocket _webSocket;
|
AsyncWebSocket _webSocket;
|
||||||
size_t _bufferSize;
|
size_t _bufferSize;
|
||||||
|
|
||||||
WebSocketConnector(StatefulService<T> * statefulService,
|
WebSocketConnector(StatefulService<T> * statefulService, AsyncWebServer * server, const char * webSocketPath, SecurityManager * securityManager, AuthenticationPredicate authenticationPredicate, size_t bufferSize)
|
||||||
AsyncWebServer * server,
|
|
||||||
const char * webSocketPath,
|
|
||||||
SecurityManager * securityManager,
|
|
||||||
AuthenticationPredicate authenticationPredicate,
|
|
||||||
size_t bufferSize)
|
|
||||||
: _statefulService(statefulService)
|
: _statefulService(statefulService)
|
||||||
, _server(server)
|
, _server(server)
|
||||||
, _webSocket(webSocketPath)
|
, _webSocket(webSocketPath)
|
||||||
, _bufferSize(bufferSize) {
|
, _bufferSize(bufferSize) {
|
||||||
_webSocket.setFilter(securityManager->filterRequest(authenticationPredicate));
|
_webSocket.setFilter(securityManager->filterRequest(authenticationPredicate));
|
||||||
_webSocket.onEvent(std::bind(&WebSocketConnector::onWSEvent,
|
_webSocket.onEvent(std::bind(&WebSocketConnector::onWSEvent, this, _1, _2, _3, _4, _5, _6));
|
||||||
this,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::placeholders::_2,
|
|
||||||
std::placeholders::_3,
|
|
||||||
std::placeholders::_4,
|
|
||||||
std::placeholders::_5,
|
|
||||||
std::placeholders::_6));
|
|
||||||
_server->addHandler(&_webSocket);
|
_server->addHandler(&_webSocket);
|
||||||
_server->on(webSocketPath, HTTP_GET, std::bind(&WebSocketConnector::forbidden, this, std::placeholders::_1));
|
_server->on(webSocketPath, HTTP_GET, std::bind(&WebSocketConnector::forbidden, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketConnector(StatefulService<T> * statefulService, AsyncWebServer * server, const char * webSocketPath, size_t bufferSize)
|
WebSocketConnector(StatefulService<T> * statefulService, AsyncWebServer * server, const char * webSocketPath, size_t bufferSize)
|
||||||
@@ -46,14 +36,7 @@ class WebSocketConnector {
|
|||||||
, _server(server)
|
, _server(server)
|
||||||
, _webSocket(webSocketPath)
|
, _webSocket(webSocketPath)
|
||||||
, _bufferSize(bufferSize) {
|
, _bufferSize(bufferSize) {
|
||||||
_webSocket.onEvent(std::bind(&WebSocketConnector::onWSEvent,
|
_webSocket.onEvent(std::bind(&WebSocketConnector::onWSEvent, this, _1, _2, _3, _4, _5, _6));
|
||||||
this,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::placeholders::_2,
|
|
||||||
std::placeholders::_3,
|
|
||||||
std::placeholders::_4,
|
|
||||||
std::placeholders::_5,
|
|
||||||
std::placeholders::_6));
|
|
||||||
_server->addHandler(&_webSocket);
|
_server->addHandler(&_webSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,11 +67,7 @@ class WebSocketTx : virtual public WebSocketConnector<T> {
|
|||||||
WebSocketConnector<T>::_statefulService->addUpdateHandler([&](const String & originId) { transmitData(nullptr, originId); }, false);
|
WebSocketConnector<T>::_statefulService->addUpdateHandler([&](const String & originId) { transmitData(nullptr, originId); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketTx(JsonStateReader<T> stateReader,
|
WebSocketTx(JsonStateReader<T> stateReader, StatefulService<T> * statefulService, AsyncWebServer * server, const char * webSocketPath, size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncWebServer * server,
|
|
||||||
const char * webSocketPath,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: WebSocketConnector<T>(statefulService, server, webSocketPath, bufferSize)
|
: WebSocketConnector<T>(statefulService, server, webSocketPath, bufferSize)
|
||||||
, _stateReader(stateReader) {
|
, _stateReader(stateReader) {
|
||||||
WebSocketConnector<T>::_statefulService->addUpdateHandler([&](const String & originId) { transmitData(nullptr, originId); }, false);
|
WebSocketConnector<T>::_statefulService->addUpdateHandler([&](const String & originId) { transmitData(nullptr, originId); }, false);
|
||||||
@@ -161,11 +140,7 @@ class WebSocketRx : virtual public WebSocketConnector<T> {
|
|||||||
, _stateUpdater(stateUpdater) {
|
, _stateUpdater(stateUpdater) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketRx(JsonStateUpdater<T> stateUpdater,
|
WebSocketRx(JsonStateUpdater<T> stateUpdater, StatefulService<T> * statefulService, AsyncWebServer * server, const char * webSocketPath, size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncWebServer * server,
|
|
||||||
const char * webSocketPath,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: WebSocketConnector<T>(statefulService, server, webSocketPath, bufferSize)
|
: WebSocketConnector<T>(statefulService, server, webSocketPath, bufferSize)
|
||||||
, _stateUpdater(stateUpdater) {
|
, _stateUpdater(stateUpdater) {
|
||||||
}
|
}
|
||||||
@@ -207,12 +182,7 @@ class WebSocketTxRx : public WebSocketTx<T>, public WebSocketRx<T> {
|
|||||||
, WebSocketRx<T>(stateUpdater, statefulService, server, webSocketPath, securityManager, authenticationPredicate, bufferSize) {
|
, WebSocketRx<T>(stateUpdater, statefulService, server, webSocketPath, securityManager, authenticationPredicate, bufferSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketTxRx(JsonStateReader<T> stateReader,
|
WebSocketTxRx(JsonStateReader<T> stateReader, JsonStateUpdater<T> stateUpdater, StatefulService<T> * statefulService, AsyncWebServer * server, const char * webSocketPath, size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
||||||
JsonStateUpdater<T> stateUpdater,
|
|
||||||
StatefulService<T> * statefulService,
|
|
||||||
AsyncWebServer * server,
|
|
||||||
const char * webSocketPath,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE)
|
|
||||||
: WebSocketConnector<T>(statefulService, server, webSocketPath, bufferSize)
|
: WebSocketConnector<T>(statefulService, server, webSocketPath, bufferSize)
|
||||||
, WebSocketTx<T>(stateReader, statefulService, server, webSocketPath, bufferSize)
|
, WebSocketTx<T>(stateReader, statefulService, server, webSocketPath, bufferSize)
|
||||||
, WebSocketRx<T>(stateUpdater, statefulService, server, webSocketPath, bufferSize) {
|
, WebSocketRx<T>(stateUpdater, statefulService, server, webSocketPath, bufferSize) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#include <WiFiScanner.h>
|
#include <WiFiScanner.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityManager) {
|
WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN));
|
server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||||
server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN));
|
server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, _1), AuthenticationPredicates::IS_ADMIN));
|
||||||
};
|
};
|
||||||
|
|
||||||
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
#ifndef WiFiScanner_h
|
#ifndef WiFiScanner_h
|
||||||
#define WiFiScanner_h
|
#define WiFiScanner_h
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
@@ -26,10 +21,6 @@ class WiFiScanner {
|
|||||||
private:
|
private:
|
||||||
void scanNetworks(AsyncWebServerRequest * request);
|
void scanNetworks(AsyncWebServerRequest * request);
|
||||||
void listNetworks(AsyncWebServerRequest * request);
|
void listNetworks(AsyncWebServerRequest * request);
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
uint8_t convertEncryptionType(uint8_t encryptionType);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // end WiFiScanner_h
|
#endif // end WiFiScanner_h
|
||||||
|
|||||||
@@ -19,13 +19,11 @@
|
|||||||
#include "uuid/syslog.h"
|
#include "uuid/syslog.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#else
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#endif
|
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
#include "../../../src/emsesp.h"
|
||||||
|
|
||||||
#ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
#ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
||||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||||
// time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637
|
// time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637
|
||||||
@@ -191,7 +189,8 @@ void SyslogService::mark_interval(unsigned long interval) {
|
|||||||
SyslogService::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content)
|
SyslogService::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content)
|
||||||
: id_(id)
|
: id_(id)
|
||||||
, content_(std::move(content)) {
|
, content_(std::move(content)) {
|
||||||
if (time_good_ || WiFi.status() == WL_CONNECTED) {
|
// Added by proddy - check for Ethernet too. This assumes the network has already started.
|
||||||
|
if (time_good_ || emsesp::EMSESP::system_.network_connected()) {
|
||||||
#if UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
#if UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
||||||
if (gettimeofday(&time_, nullptr) != 0) {
|
if (gettimeofday(&time_, nullptr) != 0) {
|
||||||
time_.tv_sec = (time_t)-1;
|
time_.tv_sec = (time_t)-1;
|
||||||
@@ -269,8 +268,8 @@ bool SyslogService::can_transmit() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (!emsesp::EMSESP::system_.network_connected()) {
|
||||||
return false;
|
return false; // added by proddy. Check Ethernet
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t now = uuid::get_uptime_ms();
|
const uint64_t now = uuid::get_uptime_ms();
|
||||||
|
|||||||
@@ -28,15 +28,16 @@ class DummySettings {
|
|||||||
bool api_enabled = true;
|
bool api_enabled = true;
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
uint16_t publish_time = 10; // seconds
|
uint16_t publish_time = 10; // seconds
|
||||||
uint8_t mqtt_qos = 0;
|
uint8_t mqtt_qos = 0;
|
||||||
bool mqtt_retain = false;
|
bool mqtt_retain = false;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
uint8_t dallas_format = 1;
|
uint8_t dallas_format = 1;
|
||||||
bool nested_format = true;
|
bool nested_format = true;
|
||||||
uint8_t ha_climate_format = 1;
|
uint8_t ha_climate_format = 1;
|
||||||
bool ha_enabled = true;
|
bool ha_enabled = true;
|
||||||
std::string base = "ems-esp";
|
String base = "ems-esp";
|
||||||
|
uint8_t subscribe_format = 0;
|
||||||
|
|
||||||
String hostname = "ems-esp";
|
String hostname = "ems-esp";
|
||||||
String jwtSecret = "ems-esp";
|
String jwtSecret = "ems-esp";
|
||||||
@@ -48,7 +49,7 @@ class DummySettings {
|
|||||||
String staticIPConfig = "";
|
String staticIPConfig = "";
|
||||||
String dnsIP1 = "";
|
String dnsIP1 = "";
|
||||||
String dnsIP2 = "";
|
String dnsIP2 = "";
|
||||||
uint8_t ethernet_profile = 0;
|
String board_profile = "CUSTOM";
|
||||||
uint16_t publish_time_boiler = 10;
|
uint16_t publish_time_boiler = 10;
|
||||||
uint16_t publish_time_thermostat = 10;
|
uint16_t publish_time_thermostat = 10;
|
||||||
uint16_t publish_time_solar = 10;
|
uint16_t publish_time_solar = 10;
|
||||||
|
|||||||
2
makefile
2
makefile
@@ -33,7 +33,7 @@ CXX_STANDARD := -std=c++11
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Defined Symbols
|
# Defined Symbols
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST
|
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEFAULT_BOARD_PROFILE=\"LOLIN\"
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Sources & Files
|
# Sources & Files
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
; example custom platformio.ini file for EMS-ESP
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
upload_protocol = espota
|
upload_protocol = espota
|
||||||
upload_flags =
|
upload_flags =
|
||||||
@@ -6,9 +8,9 @@ upload_flags =
|
|||||||
upload_port = 10.10.10.101
|
upload_port = 10.10.10.101
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
; debug_flags = -DENABLE_CORS -DEMSESP_TEST
|
; options are EMSESP_DEBUG EMSESP_UART_DEBUG EMSESP_TEST ENABLE_CORS DEMSESP_DEFAULT_BOARD_PROFILE
|
||||||
; debug_flags = -DEMSESP_DEBUG -DEMSESP_TEST
|
; debug_flags = -DENABLE_CORS -DEMSESP_DEBUG -DEMSESP_TEST -DCORS_ORIGIN=\"http://localhost:3000\"
|
||||||
debug_flags = -DEMSESP_TEST
|
; debug_flags = -DEMSESP_DEFAULT_BOARD_PROFILE=\"NODEMCU\"
|
||||||
|
|
||||||
[env:esp32]
|
[env:esp32]
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
@@ -16,4 +18,5 @@ debug_tool = esp-prog
|
|||||||
debug_init_break = tbreak setup
|
debug_init_break = tbreak setup
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
; pre:scripts/build_interface.py
|
; pre:scripts/build_interface.py
|
||||||
; scripts/rename_fw.py
|
; scripts/upload_fw.py
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +1,37 @@
|
|||||||
; PlatformIO Project Configuration File for EMS-ESP
|
; PlatformIO Project Configuration File for EMS-ESP
|
||||||
|
; override any settings with your own local ones in pio_local.ini
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
default_envs = esp32
|
default_envs = esp32
|
||||||
|
|
||||||
# override any settings with your own local ones in pio_local.ini
|
|
||||||
extra_configs =
|
extra_configs =
|
||||||
factory_settings.ini
|
factory_settings.ini
|
||||||
pio_local.ini
|
pio_local.ini
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
; default platformio compile flags are: -fno-rtti -std=c++11 -Os -mlongcalls -mtext-section-literals -falign-functions=4 -ffunction-sections -fdata-sections -fno-exceptions -Wall
|
core_build_flags =
|
||||||
core_build_flags = -Wno-deprecated-declarations
|
-Wall
|
||||||
-Wreturn-type
|
-D CORE_DEBUG_LEVEL=0
|
||||||
-DCORE_DEBUG_LEVEL=0
|
-D NDEBUG
|
||||||
-DNDEBUG
|
-D ARDUINO_ARCH_ESP32=1
|
||||||
|
-D ESP32=1
|
||||||
|
; -std=c++17 -std=gnu++17
|
||||||
|
|
||||||
esp32_build_flags = -DARDUINO_ARCH_ESP32=1
|
core_unbuild_flags =
|
||||||
-DESP32=1
|
; -std=gnu++11
|
||||||
-DBOARD_HAS_PSRAM
|
|
||||||
; -std=c17 -std=c++17 -std=gnu++17
|
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${common.core_build_flags}
|
${common.core_build_flags}
|
||||||
${factory_settings.build_flags}
|
${factory_settings.build_flags}
|
||||||
-D FT_PROJECT=1
|
|
||||||
-D FT_SECURITY=1
|
|
||||||
-D FT_MQTT=1
|
|
||||||
-D FT_OTA=1
|
|
||||||
-D FT_NTP=1
|
|
||||||
-D FT_UPLOAD_FIRMWARE=1
|
|
||||||
-D ONEWIRE_CRC16=0
|
-D ONEWIRE_CRC16=0
|
||||||
-D NO_GLOBAL_ARDUINOOTA
|
-D NO_GLOBAL_ARDUINOOTA
|
||||||
-D ARDUINOJSON_ENABLE_STD_STRING=1
|
-D ARDUINOJSON_ENABLE_STD_STRING=1
|
||||||
-D CORS_ORIGIN=\"http://localhost:3000\"
|
|
||||||
|
|
||||||
build_unflags = -Wall
|
|
||||||
-Wdeprecated-declarations
|
|
||||||
|
|
||||||
esp32_build_unflags =
|
unbuild_flags =
|
||||||
; -std=gnu++11
|
${common.core_unbuild_flags}
|
||||||
|
|
||||||
|
; these are set in your pio_local.ini
|
||||||
debug_flags =
|
debug_flags =
|
||||||
; -D EMSESP_DEBUG
|
|
||||||
; -D EMSESP_UART_DEBUG
|
|
||||||
; -D EMSESP_TEST
|
|
||||||
; -D ENABLE_CORS
|
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
@@ -52,23 +39,21 @@ monitor_speed = 115200
|
|||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
build_type = release
|
build_type = release
|
||||||
lib_ldf_mode = chain+
|
lib_ldf_mode = chain+
|
||||||
; lib_compat_mode = strict
|
|
||||||
|
|
||||||
check_tool = cppcheck, clangtidy
|
check_tool = cppcheck, clangtidy
|
||||||
check_severity = high, medium
|
check_severity = high, medium
|
||||||
check_flags =
|
check_flags =
|
||||||
cppcheck: --std=c++11 -v
|
cppcheck: --std=c++11 -v
|
||||||
clangtidy: --checks=-*,clang-analyzer-*,performance-*
|
clangtidy: --checks=-*,clang-analyzer-*,performance-*
|
||||||
|
|
||||||
; build for GitHub Actions CI
|
; build for GitHub Actions CI
|
||||||
[env:ci]
|
[env:ci]
|
||||||
extra_scripts =
|
extra_scripts = scripts/rename_fw.py
|
||||||
scripts/rename_fw.py
|
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
||||||
build_flags = ${common.build_flags} ${common.esp32_build_flags}
|
build_flags = ${common.build_flags}
|
||||||
build_unflags = ${common.build_unflags} ${common.esp32_build_unflags}
|
build_unflags = ${common.unbuild_flags}
|
||||||
|
|
||||||
[env:esp32]
|
[env:esp32]
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
@@ -76,11 +61,11 @@ extra_scripts =
|
|||||||
scripts/rename_fw.py
|
scripts/rename_fw.py
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
;platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.2
|
; platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.2
|
||||||
; ; toolchain-xtensa32 @ 2.80200.200226
|
; toolchain-xtensa32 @ 2.80200.200226
|
||||||
; ; toolchain-xtensa32 @ 5.100200.201223
|
; toolchain-xtensa32 @ 5.100200.201223
|
||||||
; toolchain-xtensa32 @ 2.80400.2020 ; c70ec8a-toolchain-xtensa32-linux_x86_64-2.80400.2020.tar.gz
|
; toolchain-xtensa32 @ 2.80400.2020
|
||||||
; platform = https://github.com/platformio/platform-espressif32.git
|
; platform = https://github.com/platformio/platform-espressif32.git
|
||||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv ; https://github.com/espressif/arduino-esp32/blob/master/tools/partitions/
|
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
||||||
build_flags = ${common.build_flags} ${common.esp32_build_flags} ${common.debug_flags}
|
build_flags = ${common.build_flags} ${common.debug_flags}
|
||||||
build_unflags = ${common.build_unflags} ${common.esp32_build_unflags}
|
build_unflags = ${common.unbuild_flags}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ def upload(source, target, env):
|
|||||||
platform = "esp" + env['PIOPLATFORM'].strip("espressif")
|
platform = "esp" + env['PIOPLATFORM'].strip("espressif")
|
||||||
|
|
||||||
if platform == 'esp8266':
|
if platform == 'esp8266':
|
||||||
call(["cmd.exe", "/c", "C:\\Users\\Paul\\OneDrive\\Desktop\\com8266.bat"])
|
call(["cmd.exe", "/c", "C:\\Users\\Paul\\Desktop\\ems-esp8266.bat"])
|
||||||
|
|
||||||
if platform == 'esp32':
|
if platform == 'esp32':
|
||||||
call(["cmd.exe", "/c", "C:\\Users\\Paul\\OneDrive\\Desktop\\com32.bat"])
|
call(["cmd.exe", "/c", "C:\\Users\\Paul\\Desktop\\ems-esp32.bat"])
|
||||||
|
|
||||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [upload])
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [upload])
|
||||||
@@ -18,10 +18,12 @@
|
|||||||
|
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
WebAPIService::WebAPIService(AsyncWebServer * server) {
|
WebAPIService::WebAPIService(AsyncWebServer * server) {
|
||||||
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, std::bind(&WebAPIService::webAPIService, this, std::placeholders::_1));
|
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, std::bind(&WebAPIService::webAPIService, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// e.g. http://ems-esp/api?device=boiler&cmd=wwtemp&data=20&id=1
|
// e.g. http://ems-esp/api?device=boiler&cmd=wwtemp&data=20&id=1
|
||||||
@@ -68,8 +70,8 @@ void WebAPIService::webAPIService(AsyncWebServerRequest * request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN);
|
DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||||
JsonObject json = doc.to<JsonObject>();
|
JsonObject json = doc.to<JsonObject>();
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
// execute the command
|
// execute the command
|
||||||
if (data.isEmpty()) {
|
if (data.isEmpty()) {
|
||||||
|
|||||||
@@ -23,15 +23,10 @@ namespace emsesp {
|
|||||||
using namespace std::placeholders; // for `_1` etc
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
WebDevicesService::WebDevicesService(AsyncWebServer * server, SecurityManager * securityManager)
|
WebDevicesService::WebDevicesService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _device_dataHandler(DEVICE_DATA_SERVICE_PATH,
|
: _device_dataHandler(DEVICE_DATA_SERVICE_PATH, securityManager->wrapCallback(std::bind(&WebDevicesService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED)) {
|
||||||
securityManager->wrapCallback(std::bind(&WebDevicesService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED)) {
|
server->on(EMSESP_DEVICES_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebDevicesService::all_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
server->on(EMSESP_DEVICES_SERVICE_PATH,
|
|
||||||
HTTP_GET,
|
|
||||||
securityManager->wrapRequest(std::bind(&WebDevicesService::all_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
|
||||||
|
|
||||||
server->on(SCAN_DEVICES_SERVICE_PATH,
|
server->on(SCAN_DEVICES_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebDevicesService::scan_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
HTTP_GET,
|
|
||||||
securityManager->wrapRequest(std::bind(&WebDevicesService::scan_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
|
||||||
|
|
||||||
_device_dataHandler.setMethod(HTTP_POST);
|
_device_dataHandler.setMethod(HTTP_POST);
|
||||||
_device_dataHandler.setMaxContentLength(256);
|
_device_dataHandler.setMaxContentLength(256);
|
||||||
|
|||||||
@@ -22,9 +22,16 @@ namespace emsesp {
|
|||||||
|
|
||||||
uint8_t WebSettings::flags_;
|
uint8_t WebSettings::flags_;
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
|
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE)
|
||||||
|
, _boardProfileHandler(EMSESP_BOARD_PROFILE_SERVICE_PATH, securityManager->wrapCallback(std::bind(&WebSettingsService::board_profile, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
|
||||||
|
_boardProfileHandler.setMethod(HTTP_POST);
|
||||||
|
_boardProfileHandler.setMaxContentLength(256);
|
||||||
|
server->addHandler(&_boardProfileHandler);
|
||||||
|
|
||||||
addUpdateHandler([&](const String & originId) { onUpdate(); }, false);
|
addUpdateHandler([&](const String & originId) { onUpdate(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,80 +57,111 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
|
|||||||
root["api_enabled"] = settings.api_enabled;
|
root["api_enabled"] = settings.api_enabled;
|
||||||
root["analog_enabled"] = settings.analog_enabled;
|
root["analog_enabled"] = settings.analog_enabled;
|
||||||
root["pbutton_gpio"] = settings.pbutton_gpio;
|
root["pbutton_gpio"] = settings.pbutton_gpio;
|
||||||
|
root["board_profile"] = settings.board_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call on initialization and also when settings are updated via web or console
|
||||||
StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) {
|
StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) {
|
||||||
std::string crc_before(40, '\0');
|
// load default GPIO configuration based on board profile
|
||||||
std::string crc_after(40, '\0');
|
std::vector<uint8_t> data; // led, dallas, rx, tx, button
|
||||||
|
settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE;
|
||||||
|
if (!System::load_board_profile(data, settings.board_profile.c_str())) {
|
||||||
|
settings.board_profile = EMSESP_DEFAULT_BOARD_PROFILE; // invalid board configuration, override the default in case it has been misspelled
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t default_led_gpio = data[0];
|
||||||
|
uint8_t default_dallas_gpio = data[1];
|
||||||
|
uint8_t default_rx_gpio = data[2];
|
||||||
|
uint8_t default_tx_gpio = data[3];
|
||||||
|
uint8_t default_pbutton_gpio = data[4];
|
||||||
|
|
||||||
|
EMSESP::logger().info(F("EMS-ESP version %s"), EMSESP_APP_VERSION);
|
||||||
|
|
||||||
|
// check to see if we have a settings file, if not it's a fresh install
|
||||||
|
if (!root.size()) {
|
||||||
|
EMSESP::logger().info(F("Initializing configuration with board profile %s"), settings.board_profile.c_str());
|
||||||
|
} else {
|
||||||
|
EMSESP::logger().info(F("Using configuration from board profile %s"), settings.board_profile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int prev;
|
||||||
reset_flags();
|
reset_flags();
|
||||||
|
|
||||||
// tx_mode, rx and tx pins
|
// tx_mode, rx and tx pins
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d%d%d"), settings.tx_mode, settings.rx_gpio, settings.tx_gpio);
|
prev = settings.tx_mode;
|
||||||
settings.tx_mode = root["tx_mode"] | EMSESP_DEFAULT_TX_MODE;
|
settings.tx_mode = root["tx_mode"] | EMSESP_DEFAULT_TX_MODE;
|
||||||
|
check_flag(prev, settings.tx_mode, ChangeFlags::UART);
|
||||||
|
prev = settings.tx_delay;
|
||||||
settings.tx_delay = root["tx_delay"] | EMSESP_DEFAULT_TX_DELAY;
|
settings.tx_delay = root["tx_delay"] | EMSESP_DEFAULT_TX_DELAY;
|
||||||
settings.rx_gpio = root["rx_gpio"] | EMSESP_DEFAULT_RX_GPIO;
|
check_flag(prev, settings.tx_delay, ChangeFlags::UART);
|
||||||
settings.tx_gpio = root["tx_gpio"] | EMSESP_DEFAULT_TX_GPIO;
|
prev = settings.rx_gpio;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d%d%d"), settings.tx_mode, settings.rx_gpio, settings.tx_gpio);
|
settings.rx_gpio = root["rx_gpio"] | default_rx_gpio;
|
||||||
if (crc_before != crc_after) {
|
check_flag(prev, settings.rx_gpio, ChangeFlags::UART);
|
||||||
add_flags(ChangeFlags::UART);
|
prev = settings.tx_gpio;
|
||||||
}
|
settings.tx_gpio = root["tx_gpio"] | default_tx_gpio;
|
||||||
|
check_flag(prev, settings.tx_gpio, ChangeFlags::UART);
|
||||||
|
|
||||||
// syslog
|
// syslog
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d%d%d%s"), settings.syslog_enabled, settings.syslog_level, settings.syslog_mark_interval, settings.syslog_host.c_str());
|
prev = settings.syslog_enabled;
|
||||||
settings.syslog_enabled = root["syslog_enabled"] | EMSESP_DEFAULT_SYSLOG_ENABLED;
|
settings.syslog_enabled = root["syslog_enabled"] | EMSESP_DEFAULT_SYSLOG_ENABLED;
|
||||||
settings.syslog_level = root["syslog_level"] | EMSESP_DEFAULT_SYSLOG_LEVEL;
|
check_flag(prev, settings.syslog_enabled, ChangeFlags::SYSLOG);
|
||||||
|
|
||||||
|
prev = settings.syslog_level;
|
||||||
|
settings.syslog_level = root["syslog_level"] | EMSESP_DEFAULT_SYSLOG_LEVEL;
|
||||||
|
check_flag(prev, settings.syslog_level, ChangeFlags::SYSLOG);
|
||||||
|
|
||||||
|
prev = settings.syslog_mark_interval;
|
||||||
settings.syslog_mark_interval = root["syslog_mark_interval"] | EMSESP_DEFAULT_SYSLOG_MARK_INTERVAL;
|
settings.syslog_mark_interval = root["syslog_mark_interval"] | EMSESP_DEFAULT_SYSLOG_MARK_INTERVAL;
|
||||||
settings.syslog_host = root["syslog_host"] | EMSESP_DEFAULT_SYSLOG_HOST;
|
check_flag(prev, settings.syslog_mark_interval, ChangeFlags::SYSLOG);
|
||||||
settings.syslog_port = root["syslog_port"] | EMSESP_DEFAULT_SYSLOG_PORT;
|
|
||||||
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
|
String old_syslog_host = settings.syslog_host;
|
||||||
EMSESP::trace_raw(settings.trace_raw);
|
settings.syslog_host = root["syslog_host"] | EMSESP_DEFAULT_SYSLOG_HOST;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d%d%d%d%s"), settings.syslog_enabled, settings.syslog_level, settings.syslog_mark_interval, settings.syslog_port, settings.syslog_host.c_str());
|
if (old_syslog_host.equals(settings.syslog_host.c_str())) {
|
||||||
if (crc_before != crc_after) {
|
|
||||||
add_flags(ChangeFlags::SYSLOG);
|
add_flags(ChangeFlags::SYSLOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prev = settings.syslog_port;
|
||||||
|
settings.syslog_port = root["syslog_port"] | EMSESP_DEFAULT_SYSLOG_PORT;
|
||||||
|
check_flag(prev, settings.syslog_port, ChangeFlags::SYSLOG);
|
||||||
|
|
||||||
|
prev = settings.trace_raw;
|
||||||
|
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
|
||||||
|
check_flag(prev, settings.trace_raw, ChangeFlags::SYSLOG);
|
||||||
|
EMSESP::trace_raw(settings.trace_raw);
|
||||||
|
|
||||||
// adc
|
// adc
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d"), settings.analog_enabled);
|
prev = settings.analog_enabled;
|
||||||
settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
|
settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d"), settings.analog_enabled);
|
check_flag(prev, settings.analog_enabled, ChangeFlags::ADC);
|
||||||
if (crc_before != crc_after) {
|
|
||||||
add_flags(ChangeFlags::ADC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// button
|
// button
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d"), settings.pbutton_gpio);
|
prev = settings.pbutton_gpio;
|
||||||
settings.pbutton_gpio = root["pbutton_gpio"] | EMSESP_DEFAULT_PBUTTON_GPIO;
|
settings.pbutton_gpio = root["pbutton_gpio"] | default_pbutton_gpio;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d"), settings.pbutton_gpio);
|
check_flag(prev, settings.pbutton_gpio, ChangeFlags::BUTTON);
|
||||||
if (crc_before != crc_after) {
|
|
||||||
add_flags(ChangeFlags::BUTTON);
|
|
||||||
}
|
|
||||||
|
|
||||||
// dallas
|
// dallas
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d%d"), settings.dallas_gpio, settings.dallas_parasite);
|
prev = settings.dallas_gpio;
|
||||||
settings.dallas_gpio = root["dallas_gpio"] | EMSESP_DEFAULT_DALLAS_GPIO;
|
settings.dallas_gpio = root["dallas_gpio"] | default_dallas_gpio;
|
||||||
|
check_flag(prev, settings.dallas_gpio, ChangeFlags::DALLAS);
|
||||||
|
prev = settings.dallas_parasite;
|
||||||
settings.dallas_parasite = root["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE;
|
settings.dallas_parasite = root["dallas_parasite"] | EMSESP_DEFAULT_DALLAS_PARASITE;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d%d"), settings.dallas_gpio, settings.dallas_parasite);
|
check_flag(prev, settings.dallas_parasite, ChangeFlags::DALLAS);
|
||||||
if (crc_before != crc_after) {
|
|
||||||
add_flags(ChangeFlags::DALLAS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// shower
|
// shower
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d%d"), settings.shower_timer, settings.shower_alert);
|
prev = settings.shower_timer;
|
||||||
settings.shower_timer = root["shower_timer"] | EMSESP_DEFAULT_SHOWER_TIMER;
|
settings.shower_timer = root["shower_timer"] | EMSESP_DEFAULT_SHOWER_TIMER;
|
||||||
|
check_flag(prev, settings.shower_timer, ChangeFlags::SHOWER);
|
||||||
|
prev = settings.shower_alert;
|
||||||
settings.shower_alert = root["shower_alert"] | EMSESP_DEFAULT_SHOWER_ALERT;
|
settings.shower_alert = root["shower_alert"] | EMSESP_DEFAULT_SHOWER_ALERT;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d%d"), settings.shower_timer, settings.shower_alert);
|
check_flag(prev, settings.shower_alert, ChangeFlags::SHOWER);
|
||||||
if (crc_before != crc_after) {
|
|
||||||
add_flags(ChangeFlags::SHOWER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// led
|
// led
|
||||||
snprintf_P(&crc_before[0], crc_before.capacity() + 1, PSTR("%d%d"), settings.led_gpio, settings.hide_led);
|
prev = settings.led_gpio;
|
||||||
settings.led_gpio = root["led_gpio"] | EMSESP_DEFAULT_LED_GPIO;
|
settings.led_gpio = root["led_gpio"] | default_led_gpio;
|
||||||
|
check_flag(prev, settings.led_gpio, ChangeFlags::LED);
|
||||||
|
prev = settings.hide_led;
|
||||||
settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED;
|
settings.hide_led = root["hide_led"] | EMSESP_DEFAULT_HIDE_LED;
|
||||||
snprintf_P(&crc_after[0], crc_after.capacity() + 1, PSTR("%d%d"), settings.led_gpio, settings.hide_led);
|
check_flag(prev, settings.hide_led, ChangeFlags::LED);
|
||||||
if (crc_before != crc_after) {
|
|
||||||
add_flags(ChangeFlags::LED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// these both need reboots to be applied
|
// these both need reboots to be applied
|
||||||
settings.ems_bus_id = root["ems_bus_id"] | EMSESP_DEFAULT_EMS_BUS_ID;
|
settings.ems_bus_id = root["ems_bus_id"] | EMSESP_DEFAULT_EMS_BUS_ID;
|
||||||
@@ -147,11 +185,12 @@ void WebSettingsService::onUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) {
|
if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) {
|
||||||
EMSESP::init_tx();
|
EMSESP::init_uart();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebSettings::has_flags(WebSettings::ChangeFlags::SYSLOG)) {
|
if (WebSettings::has_flags(WebSettings::ChangeFlags::SYSLOG)) {
|
||||||
EMSESP::system_.syslog_init(true); // reload settings
|
EMSESP::system_.syslog_init(true); // reload settings
|
||||||
|
EMSESP::system_.syslog_start(); // re-start (or stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebSettings::has_flags(WebSettings::ChangeFlags::ADC)) {
|
if (WebSettings::has_flags(WebSettings::ChangeFlags::ADC)) {
|
||||||
@@ -175,4 +214,35 @@ void WebSettingsService::save() {
|
|||||||
_fsPersistence.writeToFS();
|
_fsPersistence.writeToFS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build the json profile to send back
|
||||||
|
void WebSettingsService::board_profile(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
|
if (json.is<JsonObject>()) {
|
||||||
|
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
|
||||||
|
JsonObject root = response->getRoot();
|
||||||
|
if (json.containsKey("code")) {
|
||||||
|
String board_profile = json["code"];
|
||||||
|
std::vector<uint8_t> data; // led, dallas, rx, tx, button
|
||||||
|
// check for valid board
|
||||||
|
if (System::load_board_profile(data, board_profile.c_str())) {
|
||||||
|
root["led_gpio"] = data[0];
|
||||||
|
root["dallas_gpio"] = data[1];
|
||||||
|
root["rx_gpio"] = data[2];
|
||||||
|
root["tx_gpio"] = data[3];
|
||||||
|
root["pbutton_gpio"] = data[4];
|
||||||
|
} else {
|
||||||
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#define EMSESP_SETTINGS_FILE "/config/emsespSettings.json"
|
#define EMSESP_SETTINGS_FILE "/config/emsespSettings.json"
|
||||||
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/emsespSettings"
|
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/emsespSettings"
|
||||||
|
#define EMSESP_BOARD_PROFILE_SERVICE_PATH "/rest/boardProfile"
|
||||||
|
|
||||||
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
|
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
|
||||||
#define EMSESP_DEFAULT_TX_DELAY 0 // no delay
|
#define EMSESP_DEFAULT_TX_DELAY 0 // no delay
|
||||||
@@ -37,28 +38,23 @@
|
|||||||
#define EMSESP_DEFAULT_MASTER_THERMOSTAT 0 // not set
|
#define EMSESP_DEFAULT_MASTER_THERMOSTAT 0 // not set
|
||||||
#define EMSESP_DEFAULT_SHOWER_TIMER false
|
#define EMSESP_DEFAULT_SHOWER_TIMER false
|
||||||
#define EMSESP_DEFAULT_SHOWER_ALERT false
|
#define EMSESP_DEFAULT_SHOWER_ALERT false
|
||||||
#define EMSESP_DEFAULT_HIDE_LED true
|
#define EMSESP_DEFAULT_HIDE_LED false
|
||||||
#define EMSESP_DEFAULT_DALLAS_PARASITE false
|
#define EMSESP_DEFAULT_DALLAS_PARASITE false
|
||||||
#define EMSESP_DEFAULT_API_ENABLED false // turn off, because its insecure
|
#define EMSESP_DEFAULT_API_ENABLED false // turn off, because its insecure
|
||||||
#define EMSESP_DEFAULT_BOOL_FORMAT 1 // on/off
|
#define EMSESP_DEFAULT_BOOL_FORMAT 1 // on/off
|
||||||
#define EMSESP_DEFAULT_ANALOG_ENABLED false
|
#define EMSESP_DEFAULT_ANALOG_ENABLED false
|
||||||
|
|
||||||
// Default GPIO PIN definitions
|
#ifndef EMSESP_DEFAULT_BOARD_PROFILE
|
||||||
#if defined(ESP32)
|
#define EMSESP_DEFAULT_BOARD_PROFILE "S32" // Gateway S32
|
||||||
#define EMSESP_DEFAULT_RX_GPIO 23 // D7 on Wemos D1-32, OR 17 for UART2 on Lolin D32
|
|
||||||
#define EMSESP_DEFAULT_TX_GPIO 5 // D8 on Wemos D1-32, OR 16 for UART2 on Lolin D32
|
|
||||||
#define EMSESP_DEFAULT_DALLAS_GPIO 18 // 18 on Wemos D1-32, 14 on LOLIN D32
|
|
||||||
#define EMSESP_DEFAULT_LED_GPIO 2 // 2 on Wemos D1-32, 5 on LOLIN D32
|
|
||||||
#define EMSESP_DEFAULT_PBUTTON_GPIO 0 // default GPIO is 0 (off)
|
|
||||||
#else
|
|
||||||
// for standalone
|
|
||||||
#define EMSESP_DEFAULT_RX_GPIO 0
|
|
||||||
#define EMSESP_DEFAULT_TX_GPIO 0
|
|
||||||
#define EMSESP_DEFAULT_DALLAS_GPIO 0
|
|
||||||
#define EMSESP_DEFAULT_LED_GPIO 0
|
|
||||||
#define EMSESP_DEFAULT_PBUTTON_GPIO 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Default GPIO PIN definitions - based on Wemos/Nodemcu
|
||||||
|
#define EMSESP_DEFAULT_RX_GPIO 23 // D7
|
||||||
|
#define EMSESP_DEFAULT_TX_GPIO 5 // D8
|
||||||
|
#define EMSESP_DEFAULT_DALLAS_GPIO 18
|
||||||
|
#define EMSESP_DEFAULT_LED_GPIO 2
|
||||||
|
#define EMSESP_DEFAULT_PBUTTON_GPIO 0
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
class WebSettings {
|
class WebSettings {
|
||||||
@@ -84,6 +80,7 @@ class WebSettings {
|
|||||||
bool api_enabled;
|
bool api_enabled;
|
||||||
bool analog_enabled;
|
bool analog_enabled;
|
||||||
uint8_t pbutton_gpio;
|
uint8_t pbutton_gpio;
|
||||||
|
String board_profile;
|
||||||
|
|
||||||
static void read(WebSettings & settings, JsonObject & root);
|
static void read(WebSettings & settings, JsonObject & root);
|
||||||
static StateUpdateResult update(JsonObject & root, WebSettings & settings);
|
static StateUpdateResult update(JsonObject & root, WebSettings & settings);
|
||||||
@@ -91,16 +88,22 @@ class WebSettings {
|
|||||||
enum ChangeFlags : uint8_t {
|
enum ChangeFlags : uint8_t {
|
||||||
|
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
UART = (1 << 0),
|
UART = (1 << 0), // 1
|
||||||
SYSLOG = (1 << 1),
|
SYSLOG = (1 << 1), // 2
|
||||||
ADC = (1 << 2),
|
ADC = (1 << 2), // 4
|
||||||
DALLAS = (1 << 3),
|
DALLAS = (1 << 3), // 8
|
||||||
SHOWER = (1 << 4),
|
SHOWER = (1 << 4), // 16
|
||||||
LED = (1 << 5),
|
LED = (1 << 5), // 32
|
||||||
BUTTON = (1 << 6)
|
BUTTON = (1 << 6) // 64
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void check_flag(int prev_v, int new_v, uint8_t flag) {
|
||||||
|
if (prev_v != new_v) {
|
||||||
|
add_flags(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void add_flags(uint8_t flags) {
|
static void add_flags(uint8_t flags) {
|
||||||
flags_ |= flags;
|
flags_ |= flags;
|
||||||
}
|
}
|
||||||
@@ -113,6 +116,10 @@ class WebSettings {
|
|||||||
flags_ = ChangeFlags::NONE;
|
flags_ = ChangeFlags::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t get_flags() {
|
||||||
|
return flags_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uint8_t flags_;
|
static uint8_t flags_;
|
||||||
};
|
};
|
||||||
@@ -125,8 +132,11 @@ class WebSettingsService : public StatefulService<WebSettings> {
|
|||||||
void save();
|
void save();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpEndpoint<WebSettings> _httpEndpoint;
|
HttpEndpoint<WebSettings> _httpEndpoint;
|
||||||
FSPersistence<WebSettings> _fsPersistence;
|
FSPersistence<WebSettings> _fsPersistence;
|
||||||
|
AsyncCallbackJsonWebHandler _boardProfileHandler;
|
||||||
|
|
||||||
|
void board_profile(AsyncWebServerRequest * request, JsonVariant & json);
|
||||||
|
|
||||||
void onUpdate();
|
void onUpdate();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,12 +18,14 @@
|
|||||||
|
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
|
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
// rest endpoint for web page
|
// rest endpoint for web page
|
||||||
server->on(EMSESP_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED));
|
server->on(EMSESP_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
WiFi.onEvent(std::bind(&WebStatusService::WiFiEvent, this, std::placeholders::_1, std::placeholders::_2));
|
WiFi.onEvent(std::bind(&WebStatusService::WiFiEvent, this, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles both WiFI and Ethernet
|
// handles both WiFI and Ethernet
|
||||||
@@ -39,10 +41,11 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
#endif
|
#endif
|
||||||
EMSESP::system_.wifi_tweak();
|
EMSESP::system_.wifi_tweak();
|
||||||
EMSESP::system_.send_heartbeat();
|
EMSESP::system_.send_heartbeat();
|
||||||
|
EMSESP::system_.syslog_start();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYSTEM_EVENT_ETH_START:
|
case SYSTEM_EVENT_ETH_START:
|
||||||
EMSESP::logger().info(F("Ethernet Started"));
|
EMSESP::logger().info(F("Ethernet initialized"));
|
||||||
ETH.setHostname(EMSESP::system_.hostname().c_str());
|
ETH.setHostname(EMSESP::system_.hostname().c_str());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -53,6 +56,7 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
EMSESP::logger().info(F("Ethernet Connected with IP=%s, speed %d Mbps"), ETH.localIP().toString().c_str(), ETH.linkSpeed());
|
EMSESP::logger().info(F("Ethernet Connected with IP=%s, speed %d Mbps"), ETH.localIP().toString().c_str(), ETH.linkSpeed());
|
||||||
#endif
|
#endif
|
||||||
EMSESP::system_.send_heartbeat();
|
EMSESP::system_.send_heartbeat();
|
||||||
|
EMSESP::system_.syslog_start();
|
||||||
EMSESP::system_.ethernet_connected(true);
|
EMSESP::system_.ethernet_connected(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -26,16 +26,8 @@ uuid::log::Logger Command::logger_{F_(command), uuid::log::Facility::DAEMON};
|
|||||||
|
|
||||||
std::vector<Command::CmdFunction> Command::cmdfunctions_;
|
std::vector<Command::CmdFunction> Command::cmdfunctions_;
|
||||||
|
|
||||||
/*
|
|
||||||
static emsesp::array<Command::CmdFunction> cmdfunctions_(90, 255, 16); // reserve space for 90 commands
|
|
||||||
|
|
||||||
emsesp::array<Command::CmdFunction> * Command::commands() {
|
|
||||||
return &cmdfunctions_;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// calls a command
|
// calls a command
|
||||||
// id may be used to represent a heating circuit for example
|
// id may be used to represent a heating circuit for example, it's optional
|
||||||
// returns false if error or not found
|
// returns false if error or not found
|
||||||
bool Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
bool Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
||||||
auto cf = find_command(device_type, cmd);
|
auto cf = find_command(device_type, cmd);
|
||||||
@@ -93,25 +85,17 @@ bool Command::call(const uint8_t device_type, const char * cmd, const char * val
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add a command to the list, which does not return json
|
// add a command to the list, which does not return json
|
||||||
void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb) {
|
void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb, uint8_t flag) {
|
||||||
// if the command already exists for that device type don't add it
|
// if the command already exists for that device type don't add it
|
||||||
if (find_command(device_type, uuid::read_flash_string(cmd).c_str()) != nullptr) {
|
if (find_command(device_type, uuid::read_flash_string(cmd).c_str()) != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
cmdfunctions_.emplace_back(device_type, flag, cmd, cb, nullptr);
|
||||||
CmdFunction cf;
|
|
||||||
cf.cmd_ = cmd;
|
|
||||||
cf.device_type_ = device_type;
|
|
||||||
cf.cmdfunction_json_ = nullptr; // empty
|
|
||||||
cf.cmdfunction_ = cb;
|
|
||||||
cmdfunctions_.push(cf);
|
|
||||||
*/
|
|
||||||
cmdfunctions_.emplace_back(device_type, cmd, cb, nullptr);
|
|
||||||
|
|
||||||
// see if we need to subscribe
|
// see if we need to subscribe
|
||||||
if (Mqtt::enabled()) {
|
if (Mqtt::enabled()) {
|
||||||
Mqtt::register_command(device_type, cmd, cb);
|
Mqtt::register_command(device_type, cmd, cb, flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,16 +106,7 @@ void Command::add_with_json(const uint8_t device_type, const __FlashStringHelper
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
cmdfunctions_.emplace_back(device_type, MqttSubFlag::FLAG_NOSUB, cmd, nullptr, cb); // add command
|
||||||
CmdFunction cf;
|
|
||||||
cf.cmd_ = cmd;
|
|
||||||
cf.device_type_ = device_type;
|
|
||||||
cf.cmdfunction_json_ = cb;
|
|
||||||
cf.cmdfunction_ = nullptr; // empty
|
|
||||||
cmdfunctions_.push(cf);
|
|
||||||
*/
|
|
||||||
|
|
||||||
cmdfunctions_.emplace_back(device_type, cmd, nullptr, cb); // add command
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if a command exists for that device type
|
// see if a command exists for that device type
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
// #include "containers.h"
|
|
||||||
|
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
|
||||||
#include <uuid/log.h>
|
#include <uuid/log.h>
|
||||||
@@ -43,12 +41,14 @@ class Command {
|
|||||||
public:
|
public:
|
||||||
struct CmdFunction {
|
struct CmdFunction {
|
||||||
uint8_t device_type_; // DeviceType::
|
uint8_t device_type_; // DeviceType::
|
||||||
|
uint8_t flag_;
|
||||||
const __FlashStringHelper * cmd_;
|
const __FlashStringHelper * cmd_;
|
||||||
cmdfunction_p cmdfunction_;
|
cmdfunction_p cmdfunction_;
|
||||||
cmdfunction_json_p cmdfunction_json_;
|
cmdfunction_json_p cmdfunction_json_;
|
||||||
|
|
||||||
CmdFunction(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cmdfunction, cmdfunction_json_p cmdfunction_json)
|
CmdFunction(const uint8_t device_type, const uint8_t flag, const __FlashStringHelper * cmd, cmdfunction_p cmdfunction, cmdfunction_json_p cmdfunction_json)
|
||||||
: device_type_(device_type)
|
: device_type_(device_type)
|
||||||
|
, flag_(flag)
|
||||||
, cmd_(cmd)
|
, cmd_(cmd)
|
||||||
, cmdfunction_(cmdfunction)
|
, cmdfunction_(cmdfunction)
|
||||||
, cmdfunction_json_(cmdfunction_json) {
|
, cmdfunction_json_(cmdfunction_json) {
|
||||||
@@ -59,11 +59,9 @@ class Command {
|
|||||||
return cmdfunctions_;
|
return cmdfunctions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static emsesp::array<Command::CmdFunction> * commands();
|
|
||||||
|
|
||||||
static bool call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id, JsonObject & json);
|
static bool call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id, JsonObject & json);
|
||||||
static bool call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id);
|
static bool call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id = 0);
|
||||||
static void add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb);
|
static void add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb, uint8_t flag = 0);
|
||||||
static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb);
|
static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb);
|
||||||
static void show_all(uuid::console::Shell & shell);
|
static void show_all(uuid::console::Shell & shell);
|
||||||
static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd);
|
static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ void EMSESPShell::display_banner() {
|
|||||||
println();
|
println();
|
||||||
printfln(F("┌──────────────────────────────────────┐"));
|
printfln(F("┌──────────────────────────────────────┐"));
|
||||||
printfln(F("│ %sEMS-ESP version %-10s%s │"), COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF);
|
printfln(F("│ %sEMS-ESP version %-10s%s │"), COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF);
|
||||||
printfln(F("│ %s%shttps://github.com/emsesp/EMS-ESP%s │"), COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET);
|
printfln(F("│ %s%shttps://github.com/emsesp/EMS-ESP32%s │"), COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET);
|
||||||
printfln(F("│ │"));
|
printfln(F("│ │"));
|
||||||
printfln(F("│ type %shelp%s to show available commands │"), COLOR_UNDERLINE, COLOR_RESET);
|
printfln(F("│ type %shelp%s to show available commands │"), COLOR_UNDERLINE, COLOR_RESET);
|
||||||
printfln(F("└──────────────────────────────────────┘"));
|
printfln(F("└──────────────────────────────────────┘"));
|
||||||
@@ -300,7 +300,7 @@ void EMSESPShell::add_console_commands() {
|
|||||||
// if logging is off, the watch won't show anything, show force it back to NOTICE
|
// if logging is off, the watch won't show anything, show force it back to NOTICE
|
||||||
if (shell.log_level() < Level::NOTICE) {
|
if (shell.log_level() < Level::NOTICE) {
|
||||||
shell.log_level(Level::NOTICE);
|
shell.log_level(Level::NOTICE);
|
||||||
shell.printfln(F("Force log level to notice"));
|
shell.printfln(F("Setting log level to Notice"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (watch == EMSESP::WATCH_ON) {
|
if (watch == EMSESP::WATCH_ON) {
|
||||||
@@ -615,7 +615,7 @@ std::string EMSESPStreamConsole::console_name() {
|
|||||||
// Log order is off, err, warning, notice, info, debug, trace, all
|
// Log order is off, err, warning, notice, info, debug, trace, all
|
||||||
void Console::start() {
|
void Console::start() {
|
||||||
shell = std::make_shared<EMSESPStreamConsole>(Serial, true);
|
shell = std::make_shared<EMSESPStreamConsole>(Serial, true);
|
||||||
shell->maximum_log_messages(100); // default is 50
|
shell->maximum_log_messages(100); // default was 50
|
||||||
shell->start();
|
shell->start();
|
||||||
|
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
@@ -623,8 +623,7 @@ void Console::start() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(EMSESP_STANDALONE)
|
#if defined(EMSESP_STANDALONE)
|
||||||
// always start in su/admin mode when running tests
|
shell->add_flags(CommandFlags::ADMIN); // always start in su/admin mode when running tests
|
||||||
shell->add_flags(CommandFlags::ADMIN);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// start the telnet service
|
// start the telnet service
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ uuid::log::Logger DallasSensor::logger_{F_(dallassensor), uuid::log::Facility::D
|
|||||||
void DallasSensor::start() {
|
void DallasSensor::start() {
|
||||||
reload();
|
reload();
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
// disabled if dallas gpio is 0
|
||||||
if (dallas_gpio_) {
|
if (dallas_gpio_) {
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
bus_.begin(dallas_gpio_);
|
bus_.begin(dallas_gpio_);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
// API call
|
||||||
// API call
|
Command::add_with_json(EMSdevice::DeviceType::DALLASSENSOR, F_(info), [&](const char * value, const int8_t id, JsonObject & json) { return command_info(value, id, json); });
|
||||||
Command::add_with_json(EMSdevice::DeviceType::DALLASSENSOR, F_(info), [&](const char * value, const int8_t id, JsonObject & json) { return command_info(value, id, json); });
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the MQTT settings
|
// load the MQTT settings
|
||||||
@@ -59,6 +59,10 @@ void DallasSensor::reload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DallasSensor::loop() {
|
void DallasSensor::loop() {
|
||||||
|
if (!dallas_gpio_) {
|
||||||
|
return; // dallas gpio is 0 (disabled)
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
uint32_t time_now = uuid::get_uptime();
|
uint32_t time_now = uuid::get_uptime();
|
||||||
|
|
||||||
@@ -385,7 +389,7 @@ void DallasSensor::publish_values(const bool force) {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-dallas"); // Different ids as the other portions of the EMS-ESP
|
ids.add("ems-esp-dallas"); // Different ids as the other portions of the EMS-ESP
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
if (dallas_format == Mqtt::Dallas_Format::SENSORID) {
|
if (dallas_format == Mqtt::Dallas_Format::SENSORID) {
|
||||||
// use '_' as HA doesn't like '-' in the topic name
|
// use '_' as HA doesn't like '-' in the topic name
|
||||||
std::string topicname = sensor.to_string();
|
std::string topicname = sensor.to_string();
|
||||||
|
|||||||
@@ -28,20 +28,20 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
|||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
LOG_DEBUG(F("Adding new Boiler with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Boiler with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
// cascaded heatingsources, add some values with new tags later
|
// cascaded heatingsources, only some values per individual heatsource (hs)
|
||||||
if (device_id != EMSdevice::EMS_DEVICE_ID_BOILER) {
|
if (device_id != EMSdevice::EMS_DEVICE_ID_BOILER) {
|
||||||
// uint8_t hs = device_id - EMSdevice::EMS_DEVICE_ID_BOILER_1; // heating source number
|
uint8_t hs = device_id - EMSdevice::EMS_DEVICE_ID_BOILER_1; // heating source id, count from 0
|
||||||
// Runtime of each heatingsource in 6DC, ff
|
// Runtime of each heatingsource in 0x06DC, ff
|
||||||
// register_telegram_type(0x6DC + hs, F("CascadeMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_CascadeMessage(t); });
|
register_telegram_type(0x6DC + hs, F("CascadeMessage"), false, MAKE_PF_CB(process_CascadeMessage));
|
||||||
|
register_device_value(TAG_HS1 + hs, &burnWorkMin_, DeviceValueType::TIME, nullptr, F("burnWorkMin"), F("total burner operating time"), DeviceValueUOM::MINUTES);
|
||||||
// selBurnpower in D2 and E4
|
// selBurnpower in D2 and E4
|
||||||
// register_telegram_type(0xD2, F("CascadePowerMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_CascadePowerMessage(t); });
|
// register_telegram_type(0xD2, F("CascadePowerMessage"), false, MAKE_PF_CB(process_CascadePowerMessage));
|
||||||
// idividual Flowtemps and powervalues for each heatingsource in E4
|
// individual Flowtemps and powervalues for each heatingsource in E4
|
||||||
// register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorFastPlus(t); });
|
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, MAKE_PF_CB(process_UBAMonitorFastPlus));
|
||||||
|
register_device_value(TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, nullptr, F("selFlowTemp"), F("selected flow temperature"), DeviceValueUOM::DEGREES);
|
||||||
// register_device_value(TAG_HS1 + hs, &selFlowTemp_, DeviceValueType::UINT, nullptr, F("selFlowTemp"), F("selected flow temperature"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, nullptr, F("selBurnPow"), F("burner selected max power"), DeviceValueUOM::PERCENT);
|
||||||
// register_device_value(TAG_HS1 + hs, &selBurnPow_, DeviceValueType::UINT, nullptr, F("selBurnPow"), F("burner selected max power"), DeviceValueUOM::PERCENT);
|
register_device_value(TAG_HS1 + hs, &curFlowTemp_, DeviceValueType::USHORT, FL_(div10), F("curFlowTemp"), F("current flow temperature"), DeviceValueUOM::DEGREES);
|
||||||
// register_device_value(TAG_HS1 + hs, &curFlowTemp_, DeviceValueType::USHORT, FL_(div10), F("curFlowTemp"), F("current flow temperature"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_HS1 + hs, &curBurnPow_, DeviceValueType::UINT, nullptr, F("curBurnPow"), F("burner current power"), DeviceValueUOM::PERCENT);
|
||||||
// register_device_value(TAG_HS1 + hs, &curBurnPow_, DeviceValueType::UINT, nullptr, F("curBurnPow"), F("burner current power"), DeviceValueUOM::PERCENT);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// register values for master boiler/cascade module
|
// register values for master boiler/cascade module
|
||||||
@@ -49,59 +49,54 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
|||||||
reserve_telgram_functions(25); // reserve some space for the telegram registries, to avoid memory fragmentation
|
reserve_telgram_functions(25); // reserve some space for the telegram registries, to avoid memory fragmentation
|
||||||
|
|
||||||
// the telegram handlers...
|
// the telegram handlers...
|
||||||
register_telegram_type(0x10, F("UBAErrorMessage1"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAErrorMessage(t); });
|
register_telegram_type(0x10, F("UBAErrorMessage1"), false, MAKE_PF_CB(process_UBAErrorMessage));
|
||||||
register_telegram_type(0x11, F("UBAErrorMessage2"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAErrorMessage(t); });
|
register_telegram_type(0x11, F("UBAErrorMessage2"), false, MAKE_PF_CB(process_UBAErrorMessage));
|
||||||
register_telegram_type(0x14, F("UBATotalUptime"), true, [&](std::shared_ptr<const Telegram> t) { process_UBATotalUptime(t); });
|
register_telegram_type(0x14, F("UBATotalUptime"), true, MAKE_PF_CB(process_UBATotalUptime));
|
||||||
register_telegram_type(0x15, F("UBAMaintenanceData"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMaintenanceData(t); });
|
register_telegram_type(0x15, F("UBAMaintenanceData"), false, MAKE_PF_CB(process_UBAMaintenanceData));
|
||||||
register_telegram_type(0x16, F("UBAParameters"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameters(t); });
|
register_telegram_type(0x16, F("UBAParameters"), true, MAKE_PF_CB(process_UBAParameters));
|
||||||
register_telegram_type(0x18, F("UBAMonitorFast"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorFast(t); });
|
register_telegram_type(0x18, F("UBAMonitorFast"), false, MAKE_PF_CB(process_UBAMonitorFast));
|
||||||
register_telegram_type(0x19, F("UBAMonitorSlow"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorSlow(t); });
|
register_telegram_type(0x19, F("UBAMonitorSlow"), true, MAKE_PF_CB(process_UBAMonitorSlow));
|
||||||
register_telegram_type(0x1A, F("UBASetPoints"), false, [&](std::shared_ptr<const Telegram> t) { process_UBASetPoints(t); });
|
register_telegram_type(0x1A, F("UBASetPoints"), false, MAKE_PF_CB(process_UBASetPoints));
|
||||||
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMaintenanceStatus(t); });
|
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, MAKE_PF_CB(process_UBAMaintenanceStatus));
|
||||||
register_telegram_type(0x26, F("UBASettingsWW"), true, [&](std::shared_ptr<const Telegram> t) { process_UBASettingsWW(t); });
|
register_telegram_type(0x26, F("UBASettingsWW"), true, MAKE_PF_CB(process_UBASettingsWW));
|
||||||
register_telegram_type(0x2A, F("MC10Status"), false, [&](std::shared_ptr<const Telegram> t) { process_MC10Status(t); });
|
register_telegram_type(0x2A, F("MC10Status"), false, MAKE_PF_CB(process_MC10Status));
|
||||||
register_telegram_type(0x33, F("UBAParameterWW"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameterWW(t); });
|
register_telegram_type(0x33, F("UBAParameterWW"), true, MAKE_PF_CB(process_UBAParameterWW));
|
||||||
register_telegram_type(0x34, F("UBAMonitorWW"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorWW(t); });
|
register_telegram_type(0x34, F("UBAMonitorWW"), false, MAKE_PF_CB(process_UBAMonitorWW));
|
||||||
register_telegram_type(0x35, F("UBAFlags"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAFlags(t); });
|
register_telegram_type(0x35, F("UBAFlags"), false, MAKE_PF_CB(process_UBAFlags));
|
||||||
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAOutdoorTemp(t); });
|
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, MAKE_PF_CB(process_UBAOutdoorTemp));
|
||||||
register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorSlowPlus2(t); });
|
register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, MAKE_PF_CB(process_UBAMonitorSlowPlus2));
|
||||||
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorFastPlus(t); });
|
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, MAKE_PF_CB(process_UBAMonitorFastPlus));
|
||||||
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorSlowPlus(t); });
|
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, MAKE_PF_CB(process_UBAMonitorSlowPlus));
|
||||||
register_telegram_type(0xE6, F("UBAParametersPlus"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParametersPlus(t); });
|
register_telegram_type(0xE6, F("UBAParametersPlus"), true, MAKE_PF_CB(process_UBAParametersPlus));
|
||||||
register_telegram_type(0xE9, F("UBADHWStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBADHWStatus(t); });
|
register_telegram_type(0xE9, F("UBADHWStatus"), false, MAKE_PF_CB(process_UBADHWStatus));
|
||||||
register_telegram_type(0xEA, F("UBAParameterWWPlus"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameterWWPlus(t); });
|
register_telegram_type(0xEA, F("UBAParameterWWPlus"), true, MAKE_PF_CB(process_UBAParameterWWPlus));
|
||||||
register_telegram_type(0x494, F("UBAEnergySupplied"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAEnergySupplied(t); });
|
register_telegram_type(0x494, F("UBAEnergySupplied"), false, MAKE_PF_CB(process_UBAEnergySupplied));
|
||||||
register_telegram_type(0x495, F("UBAInformation"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAInformation(t); });
|
register_telegram_type(0x495, F("UBAInformation"), false, MAKE_PF_CB(process_UBAInformation));
|
||||||
|
|
||||||
EMSESP::send_read_request(0x10, device_id); // read last errorcode on start (only published on errors)
|
|
||||||
EMSESP::send_read_request(0x11, device_id); // read last errorcode on start (only published on errors)
|
|
||||||
EMSESP::send_read_request(0x15, device_id); // read maintenace data on start (only published on change)
|
|
||||||
EMSESP::send_read_request(0x1C, device_id); // read maintenace status on start (only published on change)
|
|
||||||
|
|
||||||
// MQTT commands for boiler topic
|
// MQTT commands for boiler topic
|
||||||
register_mqtt_cmd(F("comfort"), [&](const char * value, const int8_t id) { return set_warmwater_mode(value, id); });
|
register_mqtt_cmd(F("comfort"), MAKE_CF_CB(set_warmwater_mode));
|
||||||
register_mqtt_cmd(F("wwactivated"), [&](const char * value, const int8_t id) { return set_warmwater_activated(value, id); });
|
register_mqtt_cmd(F("wwactivated"), MAKE_CF_CB(set_warmwater_activated));
|
||||||
register_mqtt_cmd(F("wwtapactivated"), [&](const char * value, const int8_t id) { return set_tapwarmwater_activated(value, id); });
|
register_mqtt_cmd(F("wwtapactivated"), MAKE_CF_CB(set_tapwarmwater_activated));
|
||||||
register_mqtt_cmd(F("wwflowtempoffset"), [&](const char * value, const int8_t id) { return set_wWFlowTempOffset(value, id); });
|
register_mqtt_cmd(F("wwflowtempoffset"), MAKE_CF_CB(set_wWFlowTempOffset));
|
||||||
register_mqtt_cmd(F("wwmaxpower"), [&](const char * value, const int8_t id) { return set_warmwater_maxpower(value, id); });
|
register_mqtt_cmd(F("wwmaxpower"), MAKE_CF_CB(set_warmwater_maxpower));
|
||||||
register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { return set_warmwater_onetime(value, id); });
|
register_mqtt_cmd(F("wwonetime"), MAKE_CF_CB(set_warmwater_onetime));
|
||||||
register_mqtt_cmd(F("wwcircpump"), [&](const char * value, const int8_t id) { return set_warmwater_circulation_pump(value, id); });
|
register_mqtt_cmd(F("wwcircpump"), MAKE_CF_CB(set_warmwater_circulation_pump));
|
||||||
register_mqtt_cmd(F("wwcirculation"), [&](const char * value, const int8_t id) { return set_warmwater_circulation(value, id); });
|
register_mqtt_cmd(F("wwcirculation"), MAKE_CF_CB(set_warmwater_circulation));
|
||||||
register_mqtt_cmd(F("wwcircmode"), [&](const char * value, const int8_t id) { return set_warmwater_circulation_mode(value, id); });
|
register_mqtt_cmd(F("wwcircmode"), MAKE_CF_CB(set_warmwater_circulation_mode));
|
||||||
register_mqtt_cmd(F("flowtemp"), [&](const char * value, const int8_t id) { return set_flow_temp(value, id); });
|
register_mqtt_cmd(F("flowtemp"), MAKE_CF_CB(set_flow_temp));
|
||||||
register_mqtt_cmd(F("wwsettemp"), [&](const char * value, const int8_t id) { return set_warmwater_temp(value, id); });
|
register_mqtt_cmd(F("wwsettemp"), MAKE_CF_CB(set_warmwater_temp));
|
||||||
register_mqtt_cmd(F("heatingactivated"), [&](const char * value, const int8_t id) { return set_heating_activated(value, id); });
|
register_mqtt_cmd(F("heatingactivated"), MAKE_CF_CB(set_heating_activated));
|
||||||
register_mqtt_cmd(F("heatingtemp"), [&](const char * value, const int8_t id) { return set_heating_temp(value, id); });
|
register_mqtt_cmd(F("heatingtemp"), MAKE_CF_CB(set_heating_temp));
|
||||||
register_mqtt_cmd(F("burnmaxpower"), [&](const char * value, const int8_t id) { return set_max_power(value, id); });
|
register_mqtt_cmd(F("burnmaxpower"), MAKE_CF_CB(set_max_power));
|
||||||
register_mqtt_cmd(F("burnminpower"), [&](const char * value, const int8_t id) { return set_min_power(value, id); });
|
register_mqtt_cmd(F("burnminpower"), MAKE_CF_CB(set_min_power));
|
||||||
register_mqtt_cmd(F("boilhyston"), [&](const char * value, const int8_t id) { return set_hyst_on(value, id); });
|
register_mqtt_cmd(F("boilhyston"), MAKE_CF_CB(set_hyst_on));
|
||||||
register_mqtt_cmd(F("boilhystoff"), [&](const char * value, const int8_t id) { return set_hyst_off(value, id); });
|
register_mqtt_cmd(F("boilhystoff"), MAKE_CF_CB(set_hyst_off));
|
||||||
register_mqtt_cmd(F("burnperiod"), [&](const char * value, const int8_t id) { return set_burn_period(value, id); });
|
register_mqtt_cmd(F("burnperiod"), MAKE_CF_CB(set_burn_period));
|
||||||
register_mqtt_cmd(F("pumpdelay"), [&](const char * value, const int8_t id) { return set_pump_delay(value, id); });
|
register_mqtt_cmd(F("pumpdelay"), MAKE_CF_CB(set_pump_delay));
|
||||||
register_mqtt_cmd(F("maintenance"), [&](const char * value, const int8_t id) { return set_maintenance(value, id); });
|
register_mqtt_cmd(F("maintenance"), MAKE_CF_CB(set_maintenance));
|
||||||
register_mqtt_cmd(F("pumpmodmax"), [&](const char * value, const int8_t id) { return set_max_pump(value, id); });
|
register_mqtt_cmd(F("pumpmodmax"), MAKE_CF_CB(set_max_pump));
|
||||||
register_mqtt_cmd(F("pumpmodmin"), [&](const char * value, const int8_t id) { return set_min_pump(value, id); });
|
register_mqtt_cmd(F("pumpmodmin"), MAKE_CF_CB(set_min_pump));
|
||||||
// register_mqtt_cmd(F("reset"), [&](const char * value, const int8_t id) { return set_reset(value, id); });
|
register_mqtt_cmd(F("reset"), MAKE_CF_CB(set_reset));
|
||||||
|
|
||||||
// add values
|
// add values
|
||||||
reserve_device_values(50);
|
reserve_device_values(50);
|
||||||
@@ -178,12 +173,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
|||||||
register_device_value(TAG_BOILER_DATA_WW, &wWSetTemp_, DeviceValueType::UINT, nullptr, F("wWSetTemp"), F("set temperature"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_BOILER_DATA_WW, &wWSetTemp_, DeviceValueType::UINT, nullptr, F("wWSetTemp"), F("set temperature"), DeviceValueUOM::DEGREES);
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWType_, DeviceValueType::ENUM, FL_(enum_flow), F("wWType"), F("type"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWType_, DeviceValueType::ENUM, FL_(enum_flow), F("wWType"), F("type"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWComfort_, DeviceValueType::ENUM, FL_(enum_comfort), F("wWComfort"), F("comfort"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWComfort_, DeviceValueType::ENUM, FL_(enum_comfort), F("wWComfort"), F("comfort"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWFlowTempOffset_, DeviceValueType::UINT, nullptr, F("wWFlowTempOffset"), F("flow offset temperature"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWFlowTempOffset_, DeviceValueType::UINT, nullptr, F("wWFlowTempOffset"), F("flow temperature offset"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, F("wWMaxPower"), F("max power"), DeviceValueUOM::PERCENT);
|
register_device_value(TAG_BOILER_DATA_WW, &wWMaxPower_, DeviceValueType::UINT, nullptr, F("wWMaxPower"), F("max power"), DeviceValueUOM::PERCENT);
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, F("wWCircPump"), F("circulation pump available"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWCircPump_, DeviceValueType::BOOL, nullptr, F("wWCircPump"), F("circulation pump available"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWChargeType_, DeviceValueType::BOOL, FL_(enum_charge), F("wWChargeType"), F("charging type"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWChargeType_, DeviceValueType::BOOL, FL_(enum_charge), F("wWChargeType"), F("charging type"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWDisinfectionTemp_, DeviceValueType::UINT, nullptr, F("wWDisinfectionTemp"), F("disinfection temperature"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_BOILER_DATA_WW, &wWDisinfectionTemp_, DeviceValueType::UINT, nullptr, F("wWDisinfectionTemp"), F("disinfection temperature"), DeviceValueUOM::DEGREES);
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWCircPumpMode_, DeviceValueType::ENUM, FL_(enum_freq), F("wWCircPumpMode"), F("circulation pump freq"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWCircMode_, DeviceValueType::ENUM, FL_(enum_freq), F("wWCircMode"), F("circulation pump freq"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, F("wWCirc"), F("circulation active"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, F("wWCirc"), F("circulation active"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp_, DeviceValueType::USHORT, FL_(div10), F("wWCurTemp"), F("current intern temperature"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp_, DeviceValueType::USHORT, FL_(div10), F("wWCurTemp"), F("current intern temperature"), DeviceValueUOM::DEGREES);
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp2_, DeviceValueType::USHORT, FL_(div10), F("wWCurTemp2"), F("current extern temperature"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_BOILER_DATA_WW, &wWCurTemp2_, DeviceValueType::USHORT, FL_(div10), F("wWCurTemp2"), F("current extern temperature"), DeviceValueUOM::DEGREES);
|
||||||
@@ -204,6 +199,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
|||||||
register_device_value(TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, F("wWStarts"), F("# starts"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, F("wWStarts"), F("# starts"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWStarts2_, DeviceValueType::ULONG, nullptr, F("wWStarts2"), F("# control starts"));
|
register_device_value(TAG_BOILER_DATA_WW, &wWStarts2_, DeviceValueType::ULONG, nullptr, F("wWStarts2"), F("# control starts"));
|
||||||
register_device_value(TAG_BOILER_DATA_WW, &wWWorkM_, DeviceValueType::TIME, nullptr, F("wWWorkM"), F("active time"), DeviceValueUOM::MINUTES);
|
register_device_value(TAG_BOILER_DATA_WW, &wWWorkM_, DeviceValueType::TIME, nullptr, F("wWWorkM"), F("active time"), DeviceValueUOM::MINUTES);
|
||||||
|
|
||||||
|
// fetch some initial data
|
||||||
|
EMSESP::send_read_request(0x10, device_id); // read last errorcode on start (only published on errors)
|
||||||
|
EMSESP::send_read_request(0x11, device_id); // read last errorcode on start (only published on errors)
|
||||||
|
EMSESP::send_read_request(0x15, device_id); // read maintenace data on start (only published on change)
|
||||||
|
EMSESP::send_read_request(0x1C, device_id); // read maintenace status on start (only published on change)
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish HA config
|
// publish HA config
|
||||||
@@ -227,8 +228,7 @@ bool Boiler::publish_ha_config() {
|
|||||||
|
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), Mqtt::base().c_str());
|
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), Mqtt::base().c_str());
|
||||||
Mqtt::publish_ha(topic,
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
doc.as<JsonObject>()); // publish the config payload with retain flag
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -277,7 +277,7 @@ void Boiler::check_active(const bool force) {
|
|||||||
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
|
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
|
||||||
has_update(telegram->read_value(wWActivated_, 1)); // 0xFF means on
|
has_update(telegram->read_value(wWActivated_, 1)); // 0xFF means on
|
||||||
has_update(telegram->read_value(wWCircPump_, 6)); // 0xFF means on
|
has_update(telegram->read_value(wWCircPump_, 6)); // 0xFF means on
|
||||||
has_update(telegram->read_value(wWCircPumpMode_, 7)); // 1=1x3min 6=6x3min 7=continuous
|
has_update(telegram->read_value(wWCircMode_, 7)); // 1=1x3min 6=6x3min 7=continuous
|
||||||
has_update(telegram->read_value(wWChargeType_, 10)); // 0 = charge pump, 0xff = 3-way valve
|
has_update(telegram->read_value(wWChargeType_, 10)); // 0 = charge pump, 0xff = 3-way valve
|
||||||
has_update(telegram->read_value(wWSelTemp_, 2));
|
has_update(telegram->read_value(wWSelTemp_, 2));
|
||||||
has_update(telegram->read_value(wWDisinfectionTemp_, 8));
|
has_update(telegram->read_value(wWDisinfectionTemp_, 8));
|
||||||
@@ -506,7 +506,7 @@ void Boiler::process_UBAParametersPlus(std::shared_ptr<const Telegram> telegram)
|
|||||||
void Boiler::process_UBAParameterWWPlus(std::shared_ptr<const Telegram> telegram) {
|
void Boiler::process_UBAParameterWWPlus(std::shared_ptr<const Telegram> telegram) {
|
||||||
has_update(telegram->read_value(wWActivated_, 5)); // 0x01 means on
|
has_update(telegram->read_value(wWActivated_, 5)); // 0x01 means on
|
||||||
has_update(telegram->read_value(wWCircPump_, 10)); // 0x01 means yes
|
has_update(telegram->read_value(wWCircPump_, 10)); // 0x01 means yes
|
||||||
has_update(telegram->read_value(wWCircPumpMode_, 11)); // 1=1x3min... 6=6x3min, 7=continuous
|
has_update(telegram->read_value(wWCircMode_, 11)); // 1=1x3min... 6=6x3min, 7=continuous
|
||||||
// has_update(telegram->read_value(wWDisinfectTemp_, 12)); // settings, status in E9
|
// has_update(telegram->read_value(wWDisinfectTemp_, 12)); // settings, status in E9
|
||||||
// has_update(telegram->read_value(wWSelTemp_, 6)); // settings, status in E9
|
// has_update(telegram->read_value(wWSelTemp_, 6)); // settings, status in E9
|
||||||
}
|
}
|
||||||
@@ -601,19 +601,17 @@ void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram->read_value(wWSetPumpPower_, 2)); // ww pump speed/power?
|
has_update(telegram->read_value(wWSetPumpPower_, 2)); // ww pump speed/power?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0x6DC, ff for cascaded heatsources (hs)
|
||||||
|
void Boiler::process_CascadeMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
|
// uint8_t hsActivated;
|
||||||
|
// has_update(telegram->read_value(hsActivated, 0));
|
||||||
|
telegram->read_value(burnWorkMin_, 3); // this is in seconds
|
||||||
|
burnWorkMin_ /= 60;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
|
||||||
// 0x6DC, ff for cascaded heatsources (hs)
|
|
||||||
// not implemented yet, see #739
|
|
||||||
void Boiler::process_CascadeMessage(std::shared_ptr<const Telegram> telegram) {
|
|
||||||
uint8_t hs = telegram->dest - EMSdevice::EMS_DEVICE_ID_BOILER_1;
|
|
||||||
// uint8_t hsActivated;
|
|
||||||
// uint32_t hsRuntime;
|
|
||||||
// has_update(telegram->read_value(hsActivated, 0));
|
|
||||||
// has_update(telegram->read_value(hsRuntime, 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x35 - not yet implemented
|
// 0x35 - not yet implemented
|
||||||
void Boiler::process_UBAFlags(std::shared_ptr<const Telegram> telegram) {
|
void Boiler::process_UBAFlags(std::shared_ptr<const Telegram> telegram) {
|
||||||
}
|
}
|
||||||
@@ -1102,6 +1100,7 @@ bool Boiler::set_warmwater_circulation_mode(const char * value, const int8_t id)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset command
|
// Reset command
|
||||||
// 0 & 1 Reset-Mode (Manuel, others)
|
// 0 & 1 Reset-Mode (Manuel, others)
|
||||||
// 8 reset maintenance message Hxx
|
// 8 reset maintenance message Hxx
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class Boiler : public EMSdevice {
|
|||||||
uint8_t wWCircPump_; // Warm Water circulation pump available
|
uint8_t wWCircPump_; // Warm Water circulation pump available
|
||||||
uint8_t wWChargeType_; // Warm Water charge type (pump or 3-way-valve)
|
uint8_t wWChargeType_; // Warm Water charge type (pump or 3-way-valve)
|
||||||
uint8_t wWDisinfectionTemp_; // Warm Water disinfection temperature to prevent infection
|
uint8_t wWDisinfectionTemp_; // Warm Water disinfection temperature to prevent infection
|
||||||
uint8_t wWCircPumpMode_; // Warm Water circulation pump mode
|
uint8_t wWCircMode_; // Warm Water circulation pump mode
|
||||||
uint8_t wWCirc_; // Circulation on/off
|
uint8_t wWCirc_; // Circulation on/off
|
||||||
uint16_t wWCurTemp_; // Warm Water current temperature
|
uint16_t wWCurTemp_; // Warm Water current temperature
|
||||||
uint16_t wWCurTemp2_; // Warm Water current temperature storage
|
uint16_t wWCurTemp2_; // Warm Water current temperature storage
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
|
|||||||
LOG_DEBUG(F("Adding new Heat Pump module with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Heat Pump module with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
// telegram handlers
|
// telegram handlers
|
||||||
register_telegram_type(0x042B, F("HP1"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor1(t); });
|
register_telegram_type(0x042B, F("HP1"), true, MAKE_PF_CB(process_HPMonitor1));
|
||||||
register_telegram_type(0x047B, F("HP2"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor2(t); });
|
register_telegram_type(0x047B, F("HP2"), true, MAKE_PF_CB(process_HPMonitor2));
|
||||||
|
|
||||||
// device values
|
// device values
|
||||||
register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr); // empty full name to prevent being shown in web or console
|
register_device_value(TAG_NONE, &id_, DeviceValueType::UINT, nullptr, F("id"), nullptr); // empty full name to prevent being shown in web or console
|
||||||
|
|||||||
@@ -31,23 +31,25 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
|
|||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
|
||||||
if (device_id <= 0x27) {
|
if (device_id <= 0x27) {
|
||||||
// telegram handlers 0x20 - 0x27 for HC
|
// telegram handlers 0x20 - 0x27 for HC
|
||||||
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, [&](std::shared_ptr<const Telegram> t) { process_MMPLUSStatusMessage_HC(t); });
|
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, MAKE_PF_CB(process_MMPLUSStatusMessage_HC));
|
||||||
} else {
|
} else {
|
||||||
// telegram handlers for warm water/DHW 0x28, 0x29
|
// telegram handlers for warm water/DHW 0x28, 0x29
|
||||||
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, [&](std::shared_ptr<const Telegram> t) { process_MMPLUSStatusMessage_WWC(t); });
|
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, MAKE_PF_CB(process_MMPLUSStatusMessage_WWC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EMS 1.0
|
// EMS 1.0
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
|
||||||
register_telegram_type(0x00AA, F("MMConfigMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_MMConfigMessage(t); });
|
register_telegram_type(0x00AA, F("MMConfigMessage"), false, MAKE_PF_CB(process_MMConfigMessage));
|
||||||
register_telegram_type(0x00AB, F("MMStatusMessage"), true, [&](std::shared_ptr<const Telegram> t) { process_MMStatusMessage(t); });
|
register_telegram_type(0x00AB, F("MMStatusMessage"), true, MAKE_PF_CB(process_MMStatusMessage));
|
||||||
register_telegram_type(0x00AC, F("MMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_MMSetMessage(t); });
|
register_telegram_type(0x00AC, F("MMSetMessage"), false, MAKE_PF_CB(process_MMSetMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
// HT3
|
// HT3
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
||||||
register_telegram_type(0x010C, F("IPMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_IPMStatusMessage(t); });
|
register_telegram_type(0x010C, F("IPMStatusMessage"), false, MAKE_PF_CB(process_IPMStatusMessage));
|
||||||
|
register_telegram_type(0x001E, F("IPMTempMessage"), false, MAKE_PF_CB(process_IPMTempMessage));
|
||||||
|
// register_telegram_type(0x0023, F("IPMSetMessage"), false, MAKE_PF_CB(process_IPMSetMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the device values and set hc_ and type_
|
// register the device values and set hc_ and type_
|
||||||
@@ -60,6 +62,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
|
|||||||
register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), F("flowTempHc"), F("flow temperature in assigned hc (TC1)"), DeviceValueUOM::DEGREES);
|
register_device_value(tag, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), F("flowTempHc"), F("flow temperature in assigned hc (TC1)"), DeviceValueUOM::DEGREES);
|
||||||
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, F("pumpStatus"), F("pump status in assigned hc (PC1)"), DeviceValueUOM::PUMP);
|
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, F("pumpStatus"), F("pump status in assigned hc (PC1)"), DeviceValueUOM::PUMP);
|
||||||
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, F("valveStatus"), F("mixing valve actuator in assigned hc (VC1)"), DeviceValueUOM::PERCENT);
|
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, F("valveStatus"), F("mixing valve actuator in assigned hc (VC1)"), DeviceValueUOM::PERCENT);
|
||||||
|
register_device_value(tag, &flowTempVf_, DeviceValueType::USHORT, FL_(div10), F("flowTempVf"), F("flow temperature in header (T0/Vf)"), DeviceValueUOM::DEGREES);
|
||||||
} else {
|
} else {
|
||||||
type_ = Type::WWC;
|
type_ = Type::WWC;
|
||||||
hc_ = device_id - 0x28 + 1;
|
hc_ = device_id - 0x28 + 1;
|
||||||
@@ -135,7 +138,7 @@ void Mixer::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> tele
|
|||||||
has_update(telegram->read_value(status_, 11)); // temp status
|
has_update(telegram->read_value(status_, 11)); // temp status
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mixer IMP - 0x010C
|
// Mixer IPM - 0x010C
|
||||||
// e.g. A0 00 FF 00 00 0C 01 00 00 00 00 00 54
|
// e.g. A0 00 FF 00 00 0C 01 00 00 00 00 00 54
|
||||||
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
||||||
void Mixer::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
void Mixer::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
@@ -156,6 +159,13 @@ void Mixer::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram->read_value(flowSetTemp_, 5)); // flowSettemp is also in unmixed circuits, see #711
|
has_update(telegram->read_value(flowSetTemp_, 5)); // flowSettemp is also in unmixed circuits, see #711
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mixer IPM - 0x001E Temperature Message in unmixed circuits
|
||||||
|
// in unmixed circuits FlowTemp in 10C is zero, this is the measured flowtemp in header
|
||||||
|
void Mixer::process_IPMTempMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
|
|
||||||
|
has_update(telegram->read_value(flowTempVf_, 0)); // TC1, is * 10
|
||||||
|
}
|
||||||
|
|
||||||
// Mixer on a MM10 - 0xAB
|
// Mixer on a MM10 - 0xAB
|
||||||
// e.g. Mixer Module -> All, type 0xAB, telegram: 21 00 AB 00 2D 01 BE 64 04 01 00 (CRC=15) #data=7
|
// e.g. Mixer Module -> All, type 0xAB, telegram: 21 00 AB 00 2D 01 BE 64 04 01 00 (CRC=15) #data=7
|
||||||
// see also https://github.com/emsesp/EMS-ESP/issues/386
|
// see also https://github.com/emsesp/EMS-ESP/issues/386
|
||||||
@@ -187,6 +197,12 @@ void Mixer::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// pos 1: position in %
|
// pos 1: position in %
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thermostat(0x10) -> Mixer(0x21), ?(0x23), data: 1A 64 00 90 21 23 00 1A 64 00 89
|
||||||
|
void Mixer::process_IPMSetMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
|
// pos 0: flowtemp setpoint 1A = 26°C
|
||||||
|
// pos 1: position in %?
|
||||||
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ class Mixer : public EMSdevice {
|
|||||||
void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram);
|
void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);
|
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram);
|
void process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram);
|
||||||
|
void process_IPMTempMessage(std::shared_ptr<const Telegram> telegram);
|
||||||
|
void process_IPMSetMessage(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_MMStatusMessage(std::shared_ptr<const Telegram> telegram);
|
void process_MMStatusMessage(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_MMConfigMessage(std::shared_ptr<const Telegram> telegram);
|
void process_MMConfigMessage(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_MMSetMessage(std::shared_ptr<const Telegram> telegram);
|
void process_MMSetMessage(std::shared_ptr<const Telegram> telegram);
|
||||||
@@ -47,6 +49,7 @@ class Mixer : public EMSdevice {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t flowTempHc_;
|
uint16_t flowTempHc_;
|
||||||
|
uint16_t flowTempVf_;
|
||||||
uint8_t pumpStatus_;
|
uint8_t pumpStatus_;
|
||||||
int8_t status_;
|
int8_t status_;
|
||||||
uint8_t flowSetTemp_;
|
uint8_t flowSetTemp_;
|
||||||
|
|||||||
@@ -30,34 +30,34 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
|
|||||||
|
|
||||||
// telegram handlers
|
// telegram handlers
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
|
||||||
register_telegram_type(0x0097, F("SM10Monitor"), true, [&](std::shared_ptr<const Telegram> t) { process_SM10Monitor(t); });
|
register_telegram_type(0x0097, F("SM10Monitor"), true, MAKE_PF_CB(process_SM10Monitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
|
||||||
if (device_id == 0x2A) {
|
if (device_id == 0x2A) {
|
||||||
register_telegram_type(0x07D6, F("SM100wwTemperature"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100wwTemperature(t); });
|
register_telegram_type(0x07D6, F("SM100wwTemperature"), false, MAKE_PF_CB(process_SM100wwTemperature));
|
||||||
register_telegram_type(0x07AA, F("SM100wwStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100wwStatus(t); });
|
register_telegram_type(0x07AA, F("SM100wwStatus"), false, MAKE_PF_CB(process_SM100wwStatus));
|
||||||
register_telegram_type(0x07AB, F("SM100wwCommand"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100wwCommand(t); });
|
register_telegram_type(0x07AB, F("SM100wwCommand"), false, MAKE_PF_CB(process_SM100wwCommand));
|
||||||
} else {
|
} else {
|
||||||
register_telegram_type(0xF9, F("ParamCfg"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100ParamCfg(t); });
|
register_telegram_type(0xF9, F("ParamCfg"), false, MAKE_PF_CB(process_SM100ParamCfg));
|
||||||
register_telegram_type(0x0358, F("SM100SystemConfig"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100SystemConfig(t); });
|
register_telegram_type(0x0358, F("SM100SystemConfig"), true, MAKE_PF_CB(process_SM100SystemConfig));
|
||||||
register_telegram_type(0x035A, F("SM100SolarCircuitConfig"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100SolarCircuitConfig(t); });
|
register_telegram_type(0x035A, F("SM100SolarCircuitConfig"), true, MAKE_PF_CB(process_SM100SolarCircuitConfig));
|
||||||
register_telegram_type(0x0362, F("SM100Monitor"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Monitor(t); });
|
register_telegram_type(0x0362, F("SM100Monitor"), true, MAKE_PF_CB(process_SM100Monitor));
|
||||||
register_telegram_type(0x0363, F("SM100Monitor2"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Monitor2(t); });
|
register_telegram_type(0x0363, F("SM100Monitor2"), true, MAKE_PF_CB(process_SM100Monitor2));
|
||||||
register_telegram_type(0x0366, F("SM100Config"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Config(t); });
|
register_telegram_type(0x0366, F("SM100Config"), true, MAKE_PF_CB(process_SM100Config));
|
||||||
register_telegram_type(0x0364, F("SM100Status"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100Status(t); });
|
register_telegram_type(0x0364, F("SM100Status"), false, MAKE_PF_CB(process_SM100Status));
|
||||||
register_telegram_type(0x036A, F("SM100Status2"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100Status2(t); });
|
register_telegram_type(0x036A, F("SM100Status2"), false, MAKE_PF_CB(process_SM100Status2));
|
||||||
register_telegram_type(0x0380, F("SM100CollectorConfig"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100CollectorConfig(t); });
|
register_telegram_type(0x0380, F("SM100CollectorConfig"), true, MAKE_PF_CB(process_SM100CollectorConfig));
|
||||||
register_telegram_type(0x038E, F("SM100Energy"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Energy(t); });
|
register_telegram_type(0x038E, F("SM100Energy"), true, MAKE_PF_CB(process_SM100Energy));
|
||||||
register_telegram_type(0x0391, F("SM100Time"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Time(t); });
|
register_telegram_type(0x0391, F("SM100Time"), true, MAKE_PF_CB(process_SM100Time));
|
||||||
|
|
||||||
register_mqtt_cmd(F("SM100TankBottomMaxTemp"), [&](const char * value, const int8_t id) { return set_SM100TankBottomMaxTemp(value, id); });
|
register_mqtt_cmd(F("SM100TankBottomMaxTemp"), MAKE_CF_CB(set_SM100TankBottomMaxTemp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
|
||||||
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, [&](std::shared_ptr<const Telegram> t) { process_ISM1StatusMessage(t); });
|
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, MAKE_PF_CB(process_ISM1StatusMessage));
|
||||||
register_telegram_type(0x0101, F("ISM1Set"), false, [&](std::shared_ptr<const Telegram> t) { process_ISM1Set(t); });
|
register_telegram_type(0x0101, F("ISM1Set"), false, MAKE_PF_CB(process_ISM1Set));
|
||||||
}
|
}
|
||||||
|
|
||||||
// device values...
|
// device values...
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
|
|||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
LOG_DEBUG(F("Adding new Switch with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Switch with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
register_telegram_type(0x9C, F("WM10MonitorMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_WM10MonitorMessage(t); });
|
register_telegram_type(0x9C, F("WM10MonitorMessage"), false, MAKE_PF_CB(process_WM10MonitorMessage));
|
||||||
register_telegram_type(0x9D, F("WM10SetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_WM10SetMessage(t); });
|
register_telegram_type(0x9D, F("WM10SetMessage"), false, MAKE_PF_CB(process_WM10SetMessage));
|
||||||
register_telegram_type(0x1E, F("WM10TempMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_WM10TempMessage(t); });
|
register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage));
|
||||||
|
|
||||||
register_device_value(TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, F("activated"), F("activated"));
|
register_device_value(TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, F("activated"), F("activated"));
|
||||||
register_device_value(TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), F("flowTempHc"), F("flow temperature in assigned hc (TC1)"), DeviceValueUOM::DEGREES);
|
register_device_value(TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), F("flowTempHc"), F("flow temperature in assigned hc (TC1)"), DeviceValueUOM::DEGREES);
|
||||||
|
|||||||
@@ -44,18 +44,18 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
reserve_telgram_functions(25); // reserve some space for the telegram registries, to avoid memory fragmentation
|
reserve_telgram_functions(25); // reserve some space for the telegram registries, to avoid memory fragmentation
|
||||||
|
|
||||||
// common telegram handlers
|
// common telegram handlers
|
||||||
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, [&](std::shared_ptr<const Telegram> t) { process_RCOutdoorTemp(t); });
|
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, MAKE_PF_CB(process_RCOutdoorTemp));
|
||||||
register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), false, [&](std::shared_ptr<const Telegram> t) { process_RCTime(t); });
|
register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), false, MAKE_PF_CB(process_RCTime));
|
||||||
register_telegram_type(0xA2, F("RCError"), false, [&](std::shared_ptr<const Telegram> t) { process_RCError(t); });
|
register_telegram_type(0xA2, F("RCError"), false, MAKE_PF_CB(process_RCError));
|
||||||
register_telegram_type(0x12, F("RCErrorMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_RCErrorMessage(t); });
|
register_telegram_type(0x12, F("RCErrorMessage"), false, MAKE_PF_CB(process_RCErrorMessage));
|
||||||
}
|
}
|
||||||
// RC10
|
// RC10
|
||||||
if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) {
|
if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) {
|
||||||
monitor_typeids = {0xB1};
|
monitor_typeids = {0xB1};
|
||||||
set_typeids = {0xB0};
|
set_typeids = {0xB0};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC10Monitor(t); });
|
register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, MAKE_PF_CB(process_RC10Monitor));
|
||||||
register_telegram_type(set_typeids[i], F("RC10Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC10Set(t); });
|
register_telegram_type(set_typeids[i], F("RC10Set"), false, MAKE_PF_CB(process_RC10Set));
|
||||||
}
|
}
|
||||||
|
|
||||||
// RC35
|
// RC35
|
||||||
@@ -64,12 +64,12 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
set_typeids = {0x3D, 0x47, 0x51, 0x5B};
|
set_typeids = {0x3D, 0x47, 0x51, 0x5B};
|
||||||
timer_typeids = {0x3F, 0x49, 0x53, 0x5D};
|
timer_typeids = {0x3F, 0x49, 0x53, 0x5D};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC35Monitor(t); });
|
register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, MAKE_PF_CB(process_RC35Monitor));
|
||||||
register_telegram_type(set_typeids[i], F("RC35Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC35Set(t); });
|
register_telegram_type(set_typeids[i], F("RC35Set"), false, MAKE_PF_CB(process_RC35Set));
|
||||||
register_telegram_type(timer_typeids[i], F("RC35Timer"), false, [&](std::shared_ptr<const Telegram> t) { process_RC35Timer(t); });
|
register_telegram_type(timer_typeids[i], F("RC35Timer"), false, MAKE_PF_CB(process_RC35Timer));
|
||||||
}
|
}
|
||||||
register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, [&](std::shared_ptr<const Telegram> t) { process_IBASettings(t); });
|
register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, MAKE_PF_CB(process_IBASettings));
|
||||||
register_telegram_type(EMS_TYPE_wwSettings, F("WWSettings"), true, [&](std::shared_ptr<const Telegram> t) { process_RC35wwSettings(t); });
|
register_telegram_type(EMS_TYPE_wwSettings, F("WWSettings"), true, MAKE_PF_CB(process_RC35wwSettings));
|
||||||
|
|
||||||
// RC20
|
// RC20
|
||||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20) {
|
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20) {
|
||||||
@@ -77,11 +77,11 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
set_typeids = {0xA8};
|
set_typeids = {0xA8};
|
||||||
if (actual_master_thermostat == device_id) {
|
if (actual_master_thermostat == device_id) {
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Monitor(t); });
|
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, MAKE_PF_CB(process_RC20Monitor));
|
||||||
register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Set(t); });
|
register_telegram_type(set_typeids[i], F("RC20Set"), false, MAKE_PF_CB(process_RC20Set));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
register_telegram_type(0xAF, F("RC20Remote"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Remote(t); });
|
register_telegram_type(0xAF, F("RC20Remote"), false, MAKE_PF_CB(process_RC20Remote));
|
||||||
}
|
}
|
||||||
// RC20 newer
|
// RC20 newer
|
||||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20_2) {
|
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20_2) {
|
||||||
@@ -89,26 +89,26 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
set_typeids = {0xAD};
|
set_typeids = {0xAD};
|
||||||
if (actual_master_thermostat == device_id) {
|
if (actual_master_thermostat == device_id) {
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Monitor_2(t); });
|
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, MAKE_PF_CB(process_RC20Monitor_2));
|
||||||
register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Set_2(t); });
|
register_telegram_type(set_typeids[i], F("RC20Set"), false, MAKE_PF_CB(process_RC20Set_2));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
register_telegram_type(0xAF, F("RC20Remote"), false, [&](std::shared_ptr<const Telegram> t) { process_RC20Remote(t); });
|
register_telegram_type(0xAF, F("RC20Remote"), false, MAKE_PF_CB(process_RC20Remote));
|
||||||
}
|
}
|
||||||
// RC30
|
// RC30
|
||||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) {
|
} else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) {
|
||||||
monitor_typeids = {0x41};
|
monitor_typeids = {0x41};
|
||||||
set_typeids = {0xA7};
|
set_typeids = {0xA7};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC30Monitor(t); });
|
register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, MAKE_PF_CB(process_RC30Monitor));
|
||||||
register_telegram_type(set_typeids[i], F("RC30Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC30Set(t); });
|
register_telegram_type(set_typeids[i], F("RC30Set"), false, MAKE_PF_CB(process_RC30Set));
|
||||||
}
|
}
|
||||||
|
|
||||||
// EASY
|
// EASY
|
||||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) {
|
} else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) {
|
||||||
monitor_typeids = {0x0A};
|
monitor_typeids = {0x0A};
|
||||||
set_typeids = {};
|
set_typeids = {};
|
||||||
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, [&](std::shared_ptr<const Telegram> t) { process_EasyMonitor(t); });
|
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, MAKE_PF_CB(process_EasyMonitor));
|
||||||
|
|
||||||
// RC300/RC100
|
// RC300/RC100
|
||||||
} else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC300) || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
|
} else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC300) || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
|
||||||
@@ -117,36 +117,36 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
summer_typeids = {0x02AF, 0x02B0, 0x02B1, 0x02B2};
|
summer_typeids = {0x02AF, 0x02B0, 0x02B1, 0x02B2};
|
||||||
curve_typeids = {0x029B, 0x029C, 0x029D, 0x029E};
|
curve_typeids = {0x029B, 0x029C, 0x029D, 0x029E};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Monitor(t); });
|
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, MAKE_PF_CB(process_RC300Monitor));
|
||||||
register_telegram_type(set_typeids[i], F("RC300Set"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Set(t); });
|
register_telegram_type(set_typeids[i], F("RC300Set"), false, MAKE_PF_CB(process_RC300Set));
|
||||||
register_telegram_type(summer_typeids[i], F("RC300Summer"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Summer(t); });
|
register_telegram_type(summer_typeids[i], F("RC300Summer"), false, MAKE_PF_CB(process_RC300Summer));
|
||||||
register_telegram_type(curve_typeids[i], F("RC300Curves"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Curve(t); });
|
register_telegram_type(curve_typeids[i], F("RC300Curves"), false, MAKE_PF_CB(process_RC300Curve));
|
||||||
}
|
}
|
||||||
register_telegram_type(0x2F5, F("RC300WWmode"), true, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode(t); });
|
register_telegram_type(0x2F5, F("RC300WWmode"), true, MAKE_PF_CB(process_RC300WWmode));
|
||||||
register_telegram_type(0x31B, F("RC300WWtemp"), true, [&](std::shared_ptr<const Telegram> t) { process_RC300WWtemp(t); });
|
register_telegram_type(0x31B, F("RC300WWtemp"), true, MAKE_PF_CB(process_RC300WWtemp));
|
||||||
register_telegram_type(0x31D, F("RC300WWmode2"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode2(t); });
|
register_telegram_type(0x31D, F("RC300WWmode2"), false, MAKE_PF_CB(process_RC300WWmode2));
|
||||||
register_telegram_type(0x31E, F("RC300WWmode2"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300WWmode2(t); });
|
register_telegram_type(0x31E, F("RC300WWmode2"), false, MAKE_PF_CB(process_RC300WWmode2));
|
||||||
register_telegram_type(0x23A, F("RC300OutdoorTemp"), true, [&](std::shared_ptr<const Telegram> t) { process_RC300OutdoorTemp(t); });
|
register_telegram_type(0x23A, F("RC300OutdoorTemp"), true, MAKE_PF_CB(process_RC300OutdoorTemp));
|
||||||
register_telegram_type(0x267, F("RC300Floordry"), false, [&](std::shared_ptr<const Telegram> t) { process_RC300Floordry(t); });
|
register_telegram_type(0x267, F("RC300Floordry"), false, MAKE_PF_CB(process_RC300Floordry));
|
||||||
register_telegram_type(0x240, F("RC300Settings"), true, [&](std::shared_ptr<const Telegram> t) { process_RC300Settings(t); });
|
register_telegram_type(0x240, F("RC300Settings"), true, MAKE_PF_CB(process_RC300Settings));
|
||||||
|
|
||||||
// JUNKERS/HT3
|
// JUNKERS/HT3
|
||||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
|
} else if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
|
||||||
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
|
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersMonitor(t); });
|
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, MAKE_PF_CB(process_JunkersMonitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) {
|
if (has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) {
|
||||||
// FR120, FR100
|
// FR120, FR100
|
||||||
set_typeids = {0x0179, 0x017A, 0x017B, 0x017C};
|
set_typeids = {0x0179, 0x017A, 0x017B, 0x017C};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(set_typeids[i], F("JunkersSet"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersSet2(t); });
|
register_telegram_type(set_typeids[i], F("JunkersSet"), false, MAKE_PF_CB(process_JunkersSet2));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
set_typeids = {0x0165, 0x0166, 0x0167, 0x0168};
|
set_typeids = {0x0165, 0x0166, 0x0167, 0x0168};
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
register_telegram_type(set_typeids[i], F("JunkersSet"), false, [&](std::shared_ptr<const Telegram> t) { process_JunkersSet(t); });
|
register_telegram_type(set_typeids[i], F("JunkersSet"), false, MAKE_PF_CB(process_JunkersSet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,7 +377,7 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) {
|
|||||||
doc["temp_cmd_t"] = str3;
|
doc["temp_cmd_t"] = str3;
|
||||||
doc["~"] = Mqtt::base(); // ems-esp
|
doc["~"] = Mqtt::base(); // ems-esp
|
||||||
|
|
||||||
char topic_t[80];
|
char topic_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
if (Mqtt::nested_format()) {
|
if (Mqtt::nested_format()) {
|
||||||
snprintf_P(topic_t, sizeof(topic_t), PSTR("~/%s"), Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str());
|
snprintf_P(topic_t, sizeof(topic_t), PSTR("~/%s"), Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str());
|
||||||
|
|
||||||
@@ -428,7 +428,7 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) {
|
|||||||
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
// enable the a special "thermostat_hc<n>" topic to take both mode strings and floats for each of the heating circuits
|
// enable the a special "thermostat_hc<n>" topic to take both mode strings and floats for each of the heating circuits
|
||||||
std::string topic2(100, '\0');
|
std::string topic2(Mqtt::MQTT_TOPIC_MAX_SIZE, '\0');
|
||||||
snprintf_P(&topic2[0], topic2.capacity() + 1, PSTR("thermostat_hc%d"), hc_num);
|
snprintf_P(&topic2[0], topic2.capacity() + 1, PSTR("thermostat_hc%d"), hc_num);
|
||||||
register_mqtt_topic(topic2, [=](const char * m) { return thermostat_ha_cmd(m, hc_num); });
|
register_mqtt_topic(topic2, [=](const char * m) { return thermostat_ha_cmd(m, hc_num); });
|
||||||
|
|
||||||
@@ -448,9 +448,9 @@ bool Thermostat::thermostat_ha_cmd(const char * message, uint8_t hc_num) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for mode first
|
// check for mode first, which is a string
|
||||||
if (!set_mode(message, hc_num)) {
|
if (!set_mode(message, hc_num)) {
|
||||||
// handle as a numerical temperature value
|
// otherwise handle as a numerical temperature value and set the setpoint temp
|
||||||
float f = strtof((char *)message, 0);
|
float f = strtof((char *)message, 0);
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
||||||
}
|
}
|
||||||
@@ -1249,7 +1249,6 @@ bool Thermostat::set_wwonetime(const char * value, const int8_t id) {
|
|||||||
LOG_WARNING(F("Set warm water onetime: Invalid value"));
|
LOG_WARNING(F("Set warm water onetime: Invalid value"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char s[7];
|
|
||||||
LOG_INFO(F("Setting warm water onetime to %s"), b ? F_(on) : F_(off));
|
LOG_INFO(F("Setting warm water onetime to %s"), b ? F_(on) : F_(off));
|
||||||
write_command(0x02F5, 11, b ? 0xFF : 0x00, 0x031D);
|
write_command(0x02F5, 11, b ? 0xFF : 0x00, 0x031D);
|
||||||
return true;
|
return true;
|
||||||
@@ -1394,6 +1393,7 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) {
|
|||||||
data[5] = (dt[6] - '0') * 10 + (dt[7] - '0'); // sec
|
data[5] = (dt[6] - '0') * 10 + (dt[7] - '0'); // sec
|
||||||
data[6] = (dt[20] - '0'); // day of week
|
data[6] = (dt[20] - '0'); // day of week
|
||||||
data[7] = (dt[22] - '0') + 2; // DST and flag
|
data[7] = (dt[22] - '0') + 2; // DST and flag
|
||||||
|
LOG_INFO(F("Date and time: %02d.%02d.2%03d-%02d:%02d:%02d"), data[3], data[1], data[0], data[2], data[4], data[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting date and time"));
|
LOG_INFO(F("Setting date and time"));
|
||||||
@@ -1608,6 +1608,49 @@ bool Thermostat::set_controlmode(const char * value, const int8_t id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sets a single switchtime in the thermostat program for RC35
|
||||||
|
// format "01:0,1,15:30" Number, day, on, time
|
||||||
|
bool Thermostat::set_switchtime(const char * value, const int8_t id) {
|
||||||
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
|
if (hc == nullptr) {
|
||||||
|
LOG_WARNING(F("Setting switchtime: Heating Circuit %d not found or activated"), hc_num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strlen(value) != 12) {
|
||||||
|
LOG_WARNING(F("Setting switchtime: Invalid data"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t no = (value[0] - '0') * 10 + (value[1] - '0');
|
||||||
|
uint8_t day = value[3] - '0';
|
||||||
|
uint8_t on = value[5] - '0';
|
||||||
|
uint8_t time = 6 * ((value[7] - '0') * 10 + (value[8] - '0')) + (value[10] - '0');
|
||||||
|
uint8_t data[2] = {0xE7, 0x90}; // unset switchtime
|
||||||
|
|
||||||
|
if (day != 7 && on != 7) {
|
||||||
|
data[0] = (day << 5) + on;
|
||||||
|
data[1] = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no > 41 || day > 7 || (on > 1 && on != 7) || time > 0x90) {
|
||||||
|
LOG_WARNING(F("Setting switchtime: Invalid data"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_1)) {
|
||||||
|
write_command(timer_typeids[hc->hc_num() - 1], no * 2, (uint8_t *)&data, 2, timer_typeids[hc->hc_num() - 1]);
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(F("Setting switchtime: thermostat not supported"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data[0] == 0xE7) {
|
||||||
|
LOG_INFO(F("Setting switchtime no %d for heating circuit %d undefined"), no, hc->hc_num());
|
||||||
|
} else {
|
||||||
|
LOG_INFO(F("Setting switchtime no %d for heating circuit %d to day %d, %s, %02d:%d0"), no, hc->hc_num(), day, (on == 1) ? "on" : "off", time / 6, time % 6);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// sets the thermostat program for RC35 and RC20
|
// sets the thermostat program for RC35 and RC20
|
||||||
bool Thermostat::set_program(const char * value, const int8_t id) {
|
bool Thermostat::set_program(const char * value, const int8_t id) {
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
@@ -1986,74 +2029,78 @@ void Thermostat::add_commands() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// common to all thermostats
|
// common to all thermostats
|
||||||
register_mqtt_cmd(F("temp"), [&](const char * value, const int8_t id) { return set_temp(value, id); });
|
register_mqtt_cmd(F("temp"), MAKE_CF_CB(set_temp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("mode"), [&](const char * value, const int8_t id) { return set_mode(value, id); });
|
register_mqtt_cmd(F("mode"), MAKE_CF_CB(set_mode), FLAG_HC);
|
||||||
register_mqtt_cmd(F("datetime"), [&](const char * value, const int8_t id) { return set_datetime(value, id); });
|
if (model() == EMS_DEVICE_FLAG_RC35) { // section is together with RC30
|
||||||
|
register_mqtt_cmd(F("datetime"), MAKE_CF_CB(set_datetime));
|
||||||
|
}
|
||||||
|
|
||||||
switch (model()) {
|
switch (model()) {
|
||||||
case EMS_DEVICE_FLAG_RC100:
|
case EMS_DEVICE_FLAG_RC100:
|
||||||
case EMS_DEVICE_FLAG_RC300:
|
case EMS_DEVICE_FLAG_RC300:
|
||||||
register_mqtt_cmd(F("manualtemp"), [&](const char * value, const int8_t id) { return set_manualtemp(value, id); });
|
register_mqtt_cmd(F("datetime"), MAKE_CF_CB(set_datetime));
|
||||||
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { return set_ecotemp(value, id); });
|
register_mqtt_cmd(F("manualtemp"), MAKE_CF_CB(set_manualtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("comforttemp"), [&](const char * value, const int8_t id) { return set_comforttemp(value, id); });
|
register_mqtt_cmd(F("ecotemp"), MAKE_CF_CB(set_ecotemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("summermode"), [&](const char * value, const int8_t id) { return set_summermode(value, id); });
|
register_mqtt_cmd(F("comforttemp"), MAKE_CF_CB(set_comforttemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("summertemp"), [&](const char * value, const int8_t id) { return set_summertemp(value, id); });
|
register_mqtt_cmd(F("summermode"), MAKE_CF_CB(set_summermode), FLAG_HC);
|
||||||
register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { return set_wwmode(value, id); });
|
register_mqtt_cmd(F("summertemp"), MAKE_CF_CB(set_summertemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("wwsettemp"), [&](const char * value, const int8_t id) { return set_wwtemp(value, id); });
|
register_mqtt_cmd(F("wwmode"), MAKE_CF_CB(set_wwmode));
|
||||||
register_mqtt_cmd(F("wwsettemplow"), [&](const char * value, const int8_t id) { return set_wwtemplow(value, id); });
|
register_mqtt_cmd(F("wwsettemp"), MAKE_CF_CB(set_wwtemp));
|
||||||
register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { return set_wwonetime(value, id); });
|
register_mqtt_cmd(F("wwsettemplow"), MAKE_CF_CB(set_wwtemplow));
|
||||||
register_mqtt_cmd(F("wwcircmode"), [&](const char * value, const int8_t id) { return set_wwcircmode(value, id); });
|
register_mqtt_cmd(F("wwonetime"), MAKE_CF_CB(set_wwonetime));
|
||||||
register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { return set_building(value, id); });
|
register_mqtt_cmd(F("wwcircmode"), MAKE_CF_CB(set_wwcircmode));
|
||||||
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
|
register_mqtt_cmd(F("building"), MAKE_CF_CB(set_building));
|
||||||
register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { return set_designtemp(value, id); });
|
register_mqtt_cmd(F("nofrosttemp"), MAKE_CF_CB(set_nofrosttemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { return set_offsettemp(value, id); });
|
register_mqtt_cmd(F("designtemp"), MAKE_CF_CB(set_designtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("minflowtemp"), [&](const char * value, const int8_t id) { return set_minflowtemp(value, id); });
|
register_mqtt_cmd(F("offsettemp"), MAKE_CF_CB(set_offsettemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("maxflowtemp"), [&](const char * value, const int8_t id) { return set_maxflowtemp(value, id); });
|
register_mqtt_cmd(F("minflowtemp"), MAKE_CF_CB(set_minflowtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { return set_minexttemp(value, id); });
|
register_mqtt_cmd(F("maxflowtemp"), MAKE_CF_CB(set_maxflowtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("roominfluence"), [&](const char * value, const int8_t id) { return set_roominfluence(value, id); });
|
register_mqtt_cmd(F("minexttemp"), MAKE_CF_CB(set_minexttemp));
|
||||||
register_mqtt_cmd(F("program"), [&](const char * value, const int8_t id) { return set_program(value, id); });
|
register_mqtt_cmd(F("roominfluence"), MAKE_CF_CB(set_roominfluence), FLAG_HC);
|
||||||
register_mqtt_cmd(F("controlmode"), [&](const char * value, const int8_t id) { return set_controlmode(value, id); });
|
register_mqtt_cmd(F("program"), MAKE_CF_CB(set_program), FLAG_HC);
|
||||||
|
register_mqtt_cmd(F("controlmode"), MAKE_CF_CB(set_controlmode), FLAG_HC);
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_RC20_2:
|
case EMS_DEVICE_FLAG_RC20_2:
|
||||||
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); });
|
register_mqtt_cmd(F("nighttemp"), MAKE_CF_CB(set_nighttemp));
|
||||||
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { return set_daytemp(value, id); });
|
register_mqtt_cmd(F("daytemp"), MAKE_CF_CB(set_daytemp));
|
||||||
register_mqtt_cmd(F("program"), [&](const char * value, const int8_t id) { return set_program(value, id); });
|
register_mqtt_cmd(F("program"), MAKE_CF_CB(set_program));
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_RC30_1: // only RC30_1
|
case EMS_DEVICE_FLAG_RC30_1: // only RC30_1
|
||||||
register_mqtt_cmd(F("clockoffset"), [&](const char * value, const int8_t id) { return set_clockoffset(value, id); });
|
register_mqtt_cmd(F("clockoffset"), MAKE_CF_CB(set_clockoffset));
|
||||||
register_mqtt_cmd(F("language"), [&](const char * value, const int8_t id) { return set_language(value, id); });
|
register_mqtt_cmd(F("language"), MAKE_CF_CB(set_language));
|
||||||
register_mqtt_cmd(F("display"), [&](const char * value, const int8_t id) { return set_display(value, id); });
|
register_mqtt_cmd(F("display"), MAKE_CF_CB(set_display));
|
||||||
break;
|
|
||||||
case EMS_DEVICE_FLAG_RC35: // RC30 and RC35
|
case EMS_DEVICE_FLAG_RC35: // RC30 and RC35
|
||||||
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); });
|
register_mqtt_cmd(F("nighttemp"), MAKE_CF_CB(set_nighttemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { return set_daytemp(value, id); });
|
register_mqtt_cmd(F("daytemp"), MAKE_CF_CB(set_daytemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
|
register_mqtt_cmd(F("nofrosttemp"), MAKE_CF_CB(set_nofrosttemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("remotetemp"), [&](const char * value, const int8_t id) { return set_remotetemp(value, id); });
|
register_mqtt_cmd(F("remotetemp"), MAKE_CF_CB(set_remotetemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { return set_minexttemp(value, id); });
|
register_mqtt_cmd(F("minexttemp"), MAKE_CF_CB(set_minexttemp));
|
||||||
register_mqtt_cmd(F("calinttemp"), [&](const char * value, const int8_t id) { return set_calinttemp(value, id); });
|
register_mqtt_cmd(F("calinttemp"), MAKE_CF_CB(set_calinttemp));
|
||||||
register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { return set_building(value, id); });
|
register_mqtt_cmd(F("building"), MAKE_CF_CB(set_building));
|
||||||
register_mqtt_cmd(F("control"), [&](const char * value, const int8_t id) { return set_control(value, id); });
|
register_mqtt_cmd(F("control"), MAKE_CF_CB(set_control), FLAG_HC);
|
||||||
register_mqtt_cmd(F("pause"), [&](const char * value, const int8_t id) { return set_pause(value, id); });
|
register_mqtt_cmd(F("pause"), MAKE_CF_CB(set_pause), FLAG_HC);
|
||||||
register_mqtt_cmd(F("party"), [&](const char * value, const int8_t id) { return set_party(value, id); });
|
register_mqtt_cmd(F("party"), MAKE_CF_CB(set_party), FLAG_HC);
|
||||||
register_mqtt_cmd(F("holiday"), [&](const char * value, const int8_t id) { return set_holiday(value, id); });
|
register_mqtt_cmd(F("holiday"), MAKE_CF_CB(set_holiday), FLAG_HC);
|
||||||
register_mqtt_cmd(F("summertemp"), [&](const char * value, const int8_t id) { return set_summertemp(value, id); });
|
register_mqtt_cmd(F("summertemp"), MAKE_CF_CB(set_summertemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { return set_designtemp(value, id); });
|
register_mqtt_cmd(F("designtemp"), MAKE_CF_CB(set_designtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { return set_offsettemp(value, id); });
|
register_mqtt_cmd(F("offsettemp"), MAKE_CF_CB(set_offsettemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("holidaytemp"), [&](const char * value, const int8_t id) { return set_holidaytemp(value, id); });
|
register_mqtt_cmd(F("holidaytemp"), MAKE_CF_CB(set_holidaytemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { return set_wwmode(value, id); });
|
register_mqtt_cmd(F("wwmode"), MAKE_CF_CB(set_wwmode));
|
||||||
register_mqtt_cmd(F("wwcircmode"), [&](const char * value, const int8_t id) { return set_wwcircmode(value, id); });
|
register_mqtt_cmd(F("wwcircmode"), MAKE_CF_CB(set_wwcircmode));
|
||||||
register_mqtt_cmd(F("roominfluence"), [&](const char * value, const int8_t id) { return set_roominfluence(value, id); });
|
register_mqtt_cmd(F("roominfluence"), MAKE_CF_CB(set_roominfluence), FLAG_HC);
|
||||||
register_mqtt_cmd(F("flowtempoffset"), [&](const char * value, const int8_t id) { return set_flowtempoffset(value, id); });
|
register_mqtt_cmd(F("flowtempoffset"), MAKE_CF_CB(set_flowtempoffset), FLAG_HC);
|
||||||
register_mqtt_cmd(F("minflowtemp"), [&](const char * value, const int8_t id) { return set_minflowtemp(value, id); });
|
register_mqtt_cmd(F("minflowtemp"), MAKE_CF_CB(set_minflowtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("maxflowtemp"), [&](const char * value, const int8_t id) { return set_maxflowtemp(value, id); });
|
register_mqtt_cmd(F("maxflowtemp"), MAKE_CF_CB(set_maxflowtemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("reducemode"), [&](const char * value, const int8_t id) { return set_reducemode(value, id); });
|
register_mqtt_cmd(F("reducemode"), MAKE_CF_CB(set_reducemode), FLAG_HC);
|
||||||
register_mqtt_cmd(F("program"), [&](const char * value, const int8_t id) { return set_program(value, id); });
|
register_mqtt_cmd(F("program"), MAKE_CF_CB(set_program), FLAG_HC);
|
||||||
register_mqtt_cmd(F("controlmode"), [&](const char * value, const int8_t id) { return set_controlmode(value, id); });
|
register_mqtt_cmd(F("switchtime"), MAKE_CF_CB(set_switchtime), FLAG_HC);
|
||||||
|
register_mqtt_cmd(F("controlmode"), MAKE_CF_CB(set_controlmode), FLAG_HC);
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_JUNKERS:
|
case EMS_DEVICE_FLAG_JUNKERS:
|
||||||
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
|
register_mqtt_cmd(F("datetime"), MAKE_CF_CB(set_datetime));
|
||||||
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { return set_ecotemp(value, id); });
|
register_mqtt_cmd(F("nofrosttemp"), MAKE_CF_CB(set_nofrosttemp), FLAG_HC);
|
||||||
register_mqtt_cmd(F("heattemp"), [&](const char * value, const int8_t id) { return set_heattemp(value, id); });
|
register_mqtt_cmd(F("ecotemp"), MAKE_CF_CB(set_ecotemp), FLAG_HC);
|
||||||
|
register_mqtt_cmd(F("heattemp"), MAKE_CF_CB(set_heattemp), FLAG_HC);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ class Thermostat : public EMSdevice {
|
|||||||
bool set_minflowtemp(const char * value, const int8_t id);
|
bool set_minflowtemp(const char * value, const int8_t id);
|
||||||
bool set_maxflowtemp(const char * value, const int8_t id);
|
bool set_maxflowtemp(const char * value, const int8_t id);
|
||||||
bool set_reducemode(const char * value, const int8_t id);
|
bool set_reducemode(const char * value, const int8_t id);
|
||||||
|
bool set_switchtime(const char * value, const int8_t id);
|
||||||
bool set_program(const char * value, const int8_t id);
|
bool set_program(const char * value, const int8_t id);
|
||||||
bool set_controlmode(const char * value, const int8_t id);
|
bool set_controlmode(const char * value, const int8_t id);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,23 @@ static const __FlashStringHelper * const DeviceValueTAG_s[] PROGMEM = {
|
|||||||
F_(tag_wwc1), // "wwc1"
|
F_(tag_wwc1), // "wwc1"
|
||||||
F_(tag_wwc2), // "Wwc2"
|
F_(tag_wwc2), // "Wwc2"
|
||||||
F_(tag_wwc3), // "wwc3"
|
F_(tag_wwc3), // "wwc3"
|
||||||
F_(tag_wwc4) // "wwc4"
|
F_(tag_wwc4), // "wwc4"
|
||||||
|
F_(tag_hs1), // "hs1"
|
||||||
|
F_(tag_hs2), // "hs2"
|
||||||
|
F_(tag_hs3), // "hs3"
|
||||||
|
F_(tag_hs4), // "hs4"
|
||||||
|
F_(tag_hs5), // "hs5"
|
||||||
|
F_(tag_hs6), // "hs6"
|
||||||
|
F_(tag_hs7), // "hs7"
|
||||||
|
F_(tag_hs8), // "hs8"
|
||||||
|
F_(tag_hs9), // "hs9"
|
||||||
|
F_(tag_hs10), // "hs10"
|
||||||
|
F_(tag_hs11), // "hs11"
|
||||||
|
F_(tag_hs12), // "hs12"
|
||||||
|
F_(tag_hs13), // "hs13"
|
||||||
|
F_(tag_hs14), // "hs14"
|
||||||
|
F_(tag_hs15), // "hs15"
|
||||||
|
F_(tag_hs16) // "hs16"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,7 +88,23 @@ static const __FlashStringHelper * const DeviceValueTAG_mqtt[] PROGMEM = {
|
|||||||
F_(tag_wwc1), // "wwc1"
|
F_(tag_wwc1), // "wwc1"
|
||||||
F_(tag_wwc2), // "Wwc2"
|
F_(tag_wwc2), // "Wwc2"
|
||||||
F_(tag_wwc3), // "wwc3"
|
F_(tag_wwc3), // "wwc3"
|
||||||
F_(tag_wwc4) // "wwc4"
|
F_(tag_wwc4), // "wwc4"
|
||||||
|
F_(tag_hs1), // "hs1"
|
||||||
|
F_(tag_hs2), // "hs2"
|
||||||
|
F_(tag_hs3), // "hs3"
|
||||||
|
F_(tag_hs4), // "hs4"
|
||||||
|
F_(tag_hs5), // "hs5"
|
||||||
|
F_(tag_hs6), // "hs6"
|
||||||
|
F_(tag_hs7), // "hs7"
|
||||||
|
F_(tag_hs8), // "hs8"
|
||||||
|
F_(tag_hs9), // "hs9"
|
||||||
|
F_(tag_hs10), // "hs10"
|
||||||
|
F_(tag_hs11), // "hs11"
|
||||||
|
F_(tag_hs12), // "hs12"
|
||||||
|
F_(tag_hs13), // "hs13"
|
||||||
|
F_(tag_hs14), // "hs14"
|
||||||
|
F_(tag_hs15), // "hs15"
|
||||||
|
F_(tag_hs16) // "hs16"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,7 +156,7 @@ std::string EMSdevice::brand_to_string() const {
|
|||||||
return std::string{};
|
return std::string{};
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the name of the MQTT topic to use for a specific device
|
// returns the name of the MQTT topic to use for a specific device, without the base
|
||||||
std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
|
std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
|
||||||
switch (device_type) {
|
switch (device_type) {
|
||||||
case DeviceType::SYSTEM:
|
case DeviceType::SYSTEM:
|
||||||
@@ -308,6 +340,7 @@ bool EMSdevice::get_toggle_fetch(uint16_t telegram_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// list device values, only for EMSESP_DEBUG mode
|
// list device values, only for EMSESP_DEBUG mode
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
void EMSdevice::show_device_values_debug(uuid::console::Shell & shell) {
|
void EMSdevice::show_device_values_debug(uuid::console::Shell & shell) {
|
||||||
size_t total_s = 0;
|
size_t total_s = 0;
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
@@ -324,7 +357,7 @@ void EMSdevice::show_device_values_debug(uuid::console::Shell & shell) {
|
|||||||
shell.printfln("Total size of %d elements: %d", count, total_s);
|
shell.printfln("Total size of %d elements: %d", count, total_s);
|
||||||
shell.println();
|
shell.println();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// list all the telegram type IDs for this device
|
// list all the telegram type IDs for this device
|
||||||
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) {
|
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) {
|
||||||
@@ -351,7 +384,6 @@ char * EMSdevice::show_telegram_handlers(char * result) {
|
|||||||
|
|
||||||
char str[10];
|
char str[10];
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
// for (const auto & tf : *telegram_functions_) {
|
|
||||||
for (const auto & tf : telegram_functions_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
snprintf_P(str, sizeof(str), PSTR("0x%02X"), tf.telegram_type_id_);
|
snprintf_P(str, sizeof(str), PSTR("0x%02X"), tf.telegram_type_id_);
|
||||||
strlcat(result, str, 200);
|
strlcat(result, str, 200);
|
||||||
@@ -373,11 +405,11 @@ void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add command to library
|
// add command to library
|
||||||
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f) {
|
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f, uint8_t flag) {
|
||||||
Command::add(device_type_, cmd, f);
|
Command::add(device_type_, cmd, f, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register a call back function for a specific telegram type
|
// register a callback function for a specific telegram type
|
||||||
void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p f) {
|
void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p f) {
|
||||||
telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, f);
|
telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, f);
|
||||||
}
|
}
|
||||||
@@ -571,8 +603,6 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
|
|||||||
// we have a tag if it matches the filter given, and that the tag name is not empty/""
|
// we have a tag if it matches the filter given, and that the tag name is not empty/""
|
||||||
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty());
|
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty());
|
||||||
|
|
||||||
// EMSESP::logger().info(F("**HERE: console=%d nested=%d tag_filter=%d tag=%d type=%d short=%s"), console, nested, tag_filter, dv.tag, dv.type, uuid::read_flash_string(dv.short_name).c_str());
|
|
||||||
|
|
||||||
char name[80];
|
char name[80];
|
||||||
if (console) {
|
if (console) {
|
||||||
// prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic
|
// prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic
|
||||||
|
|||||||
@@ -83,6 +83,22 @@ MAKE_PSTR(tag_wwc1, "wwc1")
|
|||||||
MAKE_PSTR(tag_wwc2, "wwc2")
|
MAKE_PSTR(tag_wwc2, "wwc2")
|
||||||
MAKE_PSTR(tag_wwc3, "wwc3")
|
MAKE_PSTR(tag_wwc3, "wwc3")
|
||||||
MAKE_PSTR(tag_wwc4, "wwc4")
|
MAKE_PSTR(tag_wwc4, "wwc4")
|
||||||
|
MAKE_PSTR(tag_hs1, "hs1")
|
||||||
|
MAKE_PSTR(tag_hs2, "hs2")
|
||||||
|
MAKE_PSTR(tag_hs3, "hs3")
|
||||||
|
MAKE_PSTR(tag_hs4, "hs4")
|
||||||
|
MAKE_PSTR(tag_hs5, "hs5")
|
||||||
|
MAKE_PSTR(tag_hs6, "hs6")
|
||||||
|
MAKE_PSTR(tag_hs7, "hs7")
|
||||||
|
MAKE_PSTR(tag_hs8, "hs8")
|
||||||
|
MAKE_PSTR(tag_hs9, "hs9")
|
||||||
|
MAKE_PSTR(tag_hs10, "hs10")
|
||||||
|
MAKE_PSTR(tag_hs11, "hs11")
|
||||||
|
MAKE_PSTR(tag_hs12, "hs12")
|
||||||
|
MAKE_PSTR(tag_hs13, "hs13")
|
||||||
|
MAKE_PSTR(tag_hs14, "hs14")
|
||||||
|
MAKE_PSTR(tag_hs15, "hs15")
|
||||||
|
MAKE_PSTR(tag_hs16, "hs16")
|
||||||
|
|
||||||
// MQTT topic names
|
// MQTT topic names
|
||||||
MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat")
|
MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat")
|
||||||
@@ -102,10 +118,34 @@ enum DeviceValueTAG : uint8_t {
|
|||||||
TAG_WWC1,
|
TAG_WWC1,
|
||||||
TAG_WWC2,
|
TAG_WWC2,
|
||||||
TAG_WWC3,
|
TAG_WWC3,
|
||||||
TAG_WWC4
|
TAG_WWC4,
|
||||||
|
TAG_HS1,
|
||||||
|
TAG_HS2,
|
||||||
|
TAG_HS3,
|
||||||
|
TAG_HS4,
|
||||||
|
TAG_HS5,
|
||||||
|
TAG_HS6,
|
||||||
|
TAG_HS7,
|
||||||
|
TAG_HS8,
|
||||||
|
TAG_HS9,
|
||||||
|
TAG_HS10,
|
||||||
|
TAG_HS11,
|
||||||
|
TAG_HS12,
|
||||||
|
TAG_HS13,
|
||||||
|
TAG_HS14,
|
||||||
|
TAG_HS15,
|
||||||
|
TAG_HS16
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// mqtt flags for command subscriptions
|
||||||
|
enum MqttSubFlag : uint8_t {
|
||||||
|
FLAG_NORMAL = 0,
|
||||||
|
FLAG_HC,
|
||||||
|
FLAG_WWC,
|
||||||
|
FLAG_NOSUB
|
||||||
|
};
|
||||||
|
|
||||||
class EMSdevice {
|
class EMSdevice {
|
||||||
public:
|
public:
|
||||||
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
|
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
|
||||||
@@ -242,7 +282,7 @@ class EMSdevice {
|
|||||||
void read_command(const uint16_t type_id);
|
void read_command(const uint16_t type_id);
|
||||||
|
|
||||||
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
|
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
|
||||||
void register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f);
|
void register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f, uint8_t flag = 0);
|
||||||
|
|
||||||
void publish_mqtt_ha_sensor();
|
void publish_mqtt_ha_sensor();
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ std::vector<std::unique_ptr<EMSdevice>> EMSESP::emsdevices; // array of all
|
|||||||
std::vector<EMSESP::Device_record> EMSESP::device_library_; // library of all our known EMS devices, in heap
|
std::vector<EMSESP::Device_record> EMSESP::device_library_; // library of all our known EMS devices, in heap
|
||||||
|
|
||||||
uuid::log::Logger EMSESP::logger_{F_(emsesp), uuid::log::Facility::KERN};
|
uuid::log::Logger EMSESP::logger_{F_(emsesp), uuid::log::Facility::KERN};
|
||||||
|
uuid::log::Logger EMSESP::logger() {
|
||||||
|
return logger_;
|
||||||
|
}
|
||||||
|
|
||||||
// The services
|
// The services
|
||||||
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
|
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
|
||||||
@@ -157,19 +160,28 @@ void EMSESP::watch_id(uint16_t watch_id) {
|
|||||||
watch_id_ = watch_id;
|
watch_id_ = watch_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// change the tx_mode
|
|
||||||
// resets all counters and bumps the UART
|
// resets all counters and bumps the UART
|
||||||
// this is called when the tx_mode is persisted in the FS either via Web UI or the console
|
// this is called when the tx_mode is persisted in the FS either via Web UI or the console
|
||||||
void EMSESP::init_tx() {
|
void EMSESP::init_uart() {
|
||||||
uint8_t tx_mode;
|
uint8_t tx_mode;
|
||||||
|
uint8_t rx_gpio;
|
||||||
|
uint8_t tx_gpio;
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
tx_mode = settings.tx_mode;
|
tx_mode = settings.tx_mode;
|
||||||
tx_delay_ = settings.tx_delay * 1000;
|
tx_delay_ = settings.tx_delay * 1000;
|
||||||
|
rx_gpio = settings.rx_gpio;
|
||||||
EMSuart::stop();
|
tx_gpio = settings.tx_gpio;
|
||||||
EMSuart::start(tx_mode, settings.rx_gpio, settings.tx_gpio);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EMSuart::stop();
|
||||||
|
|
||||||
|
// don't start UART if we have invalid GPIOs
|
||||||
|
if (System::is_valid_gpio(rx_gpio) && System::is_valid_gpio(tx_gpio)) {
|
||||||
|
EMSuart::start(tx_mode, rx_gpio, tx_gpio); // start UART
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(F("Invalid UART Rx/Tx GPIOs. Check config."));
|
||||||
|
}
|
||||||
|
|
||||||
txservice_.start(); // sends out request to EMS bus for all devices
|
txservice_.start(); // sends out request to EMS bus for all devices
|
||||||
|
|
||||||
// force a fetch for all new values, unless Tx is set to off
|
// force a fetch for all new values, unless Tx is set to off
|
||||||
@@ -187,19 +199,21 @@ uint8_t EMSESP::bus_status() {
|
|||||||
// check if we have Tx issues.
|
// check if we have Tx issues.
|
||||||
uint32_t total_sent = txservice_.telegram_read_count() + txservice_.telegram_write_count();
|
uint32_t total_sent = txservice_.telegram_read_count() + txservice_.telegram_write_count();
|
||||||
|
|
||||||
// nothing sent successfully, also no errors - must be ok
|
// nothing sent and also no errors - must be ok
|
||||||
if ((total_sent == 0) && (txservice_.telegram_fail_count() == 0)) {
|
if ((total_sent == 0) && (txservice_.telegram_fail_count() == 0)) {
|
||||||
return BUS_STATUS_CONNECTED;
|
return BUS_STATUS_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// nothing sent successfully, but have Tx errors
|
// nothing sent, but have Tx errors
|
||||||
if ((total_sent == 0) && (txservice_.telegram_fail_count() != 0)) {
|
if ((total_sent == 0) && (txservice_.telegram_fail_count() != 0)) {
|
||||||
return BUS_STATUS_TX_ERRORS;
|
return BUS_STATUS_TX_ERRORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx Failure rate > 5%
|
// Tx Failure rate > 10%
|
||||||
if (((txservice_.telegram_fail_count() * 100) / total_sent) > EMSbus::EMS_TX_ERROR_LIMIT) {
|
if (txservice_.telegram_fail_count() < total_sent) {
|
||||||
return BUS_STATUS_TX_ERRORS;
|
if (((txservice_.telegram_fail_count() * 100) / total_sent) > EMSbus::EMS_TX_ERROR_LIMIT) {
|
||||||
|
return BUS_STATUS_TX_ERRORS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BUS_STATUS_CONNECTED;
|
return BUS_STATUS_CONNECTED;
|
||||||
@@ -308,8 +322,6 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
|
|||||||
char s[10];
|
char s[10];
|
||||||
shell.print(Helpers::render_value(s, (float)data.as<float>(), 1));
|
shell.print(Helpers::render_value(s, (float)data.as<float>(), 1));
|
||||||
} else if (data.is<bool>()) {
|
} else if (data.is<bool>()) {
|
||||||
char s[10];
|
|
||||||
// shell.print(Helpers::render_boolean(s, data.as<bool>()));
|
|
||||||
shell.print(data.as<bool>() ? F_(on) : F_(off));
|
shell.print(data.as<bool>() ? F_(on) : F_(off));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +498,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
|
|||||||
|
|
||||||
// publish it under a single topic, only if we have data to publish
|
// publish it under a single topic, only if we have data to publish
|
||||||
if (need_publish) {
|
if (need_publish) {
|
||||||
char topic[20];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("%s_data"), EMSdevice::device_type_2_device_name(device_type).c_str());
|
snprintf_P(topic, sizeof(topic), PSTR("%s_data"), EMSdevice::device_type_2_device_name(device_type).c_str());
|
||||||
Mqtt::publish(topic, json);
|
Mqtt::publish(topic, json);
|
||||||
}
|
}
|
||||||
@@ -579,9 +591,11 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
dest_name = device_tostring(dest);
|
dest_name = device_tostring(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for global/common types like Version
|
// check for global/common types like Version & UBADevices
|
||||||
if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) {
|
if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) {
|
||||||
type_name = read_flash_string(F("Version"));
|
type_name = read_flash_string(F("Version"));
|
||||||
|
} else if (telegram->type_id == EMSdevice::EMS_TYPE_UBADevices) {
|
||||||
|
type_name = read_flash_string(F("UBADevices"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't know the type show
|
// if we don't know the type show
|
||||||
@@ -688,7 +702,7 @@ void EMSESP::process_version(std::shared_ptr<const Telegram> telegram) {
|
|||||||
uint8_t product_id = telegram->message_data[offset]; // product ID
|
uint8_t product_id = telegram->message_data[offset]; // product ID
|
||||||
|
|
||||||
// get version as XX.XX
|
// get version as XX.XX
|
||||||
std::string version(5, '\0');
|
std::string version(6, '\0');
|
||||||
snprintf_P(&version[0], version.capacity() + 1, PSTR("%02d.%02d"), telegram->message_data[offset + 1], telegram->message_data[offset + 2]);
|
snprintf_P(&version[0], version.capacity() + 1, PSTR("%02d.%02d"), telegram->message_data[offset + 1], telegram->message_data[offset + 2]);
|
||||||
|
|
||||||
// some devices store the protocol type (HT3, Buderus) in the last byte
|
// some devices store the protocol type (HT3, Buderus) in the last byte
|
||||||
@@ -824,7 +838,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
|
|||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
emsdevice->show_mqtt_handlers(shell);
|
emsdevice->show_mqtt_handlers(shell);
|
||||||
shell.println();
|
shell.println();
|
||||||
emsdevice->show_device_values_debug(shell);
|
// emsdevice->show_device_values_debug(shell);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
shell.println();
|
shell.println();
|
||||||
@@ -1081,27 +1095,28 @@ void EMSESP::start() {
|
|||||||
// start the file system
|
// start the file system
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
if (!LITTLEFS.begin(true)) {
|
if (!LITTLEFS.begin(true)) {
|
||||||
Serial.println("LITTLEFS Mount Failed");
|
Serial.println("LITTLEFS Mount Failed. EMS-ESP stopped.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
|
esp8266React.begin(); // loads system settings (network, mqtt, etc)
|
||||||
webSettingsService.begin(); // load EMS-ESP specific settings
|
|
||||||
|
|
||||||
system_.check_upgrade(); // do any upgrades
|
system_.check_upgrade(); // do any system upgrades
|
||||||
|
|
||||||
// Load our library of known devices into stack mem. Names are stored in Flash memory (take about 960bytes)
|
// Load our library of known devices into stack mem. Names are stored in Flash memory (takes up about 1kb)
|
||||||
device_library_ = {
|
device_library_ = {
|
||||||
#include "device_library.h"
|
#include "device_library.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
console_.start(); // telnet and serial console
|
console_.start(); // telnet and serial console
|
||||||
mqtt_.start(); // mqtt init
|
|
||||||
system_.start(heap_start); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
|
webSettingsService.begin(); // load EMS-ESP specific settings, like GPIO configurations
|
||||||
shower_.start(); // initialize shower timer and shower alert
|
mqtt_.start(); // mqtt init
|
||||||
dallassensor_.start(); // dallas external sensors
|
system_.start(heap_start); // starts commands, led, adc, button, network, syslog & uart
|
||||||
webServer.begin(); // start web server
|
shower_.start(); // initialize shower timer and shower alert
|
||||||
|
dallassensor_.start(); // dallas external sensors
|
||||||
|
webServer.begin(); // start web server
|
||||||
|
|
||||||
emsdevices.reserve(5); // reserve space for initially 5 devices to avoid mem frag issues
|
emsdevices.reserve(5); // reserve space for initially 5 devices to avoid mem frag issues
|
||||||
|
|
||||||
@@ -1115,25 +1130,24 @@ void EMSESP::start() {
|
|||||||
// main loop calling all services
|
// main loop calling all services
|
||||||
void EMSESP::loop() {
|
void EMSESP::loop() {
|
||||||
esp8266React.loop(); // web
|
esp8266React.loop(); // web
|
||||||
|
system_.loop(); // does LED and checks system health, and syslog service
|
||||||
|
|
||||||
// if we're doing an OTA upload, skip MQTT and EMS
|
// if we're doing an OTA upload, skip MQTT and EMS
|
||||||
if (system_.upload_status()) {
|
if (!system_.upload_status()) {
|
||||||
return;
|
rxservice_.loop(); // process any incoming Rx telegrams
|
||||||
|
shower_.loop(); // check for shower on/off
|
||||||
|
dallassensor_.loop(); // read dallas sensor temperatures
|
||||||
|
publish_all_loop(); // with HA messages in parts to avoid flooding the mqtt queue
|
||||||
|
mqtt_.loop(); // sends out anything in the MQTT queue
|
||||||
|
|
||||||
|
// force a query on the EMS devices to fetch latest data at a set interval (1 min)
|
||||||
|
if ((uuid::get_uptime() - last_fetch_ > EMS_FETCH_FREQUENCY)) {
|
||||||
|
last_fetch_ = uuid::get_uptime();
|
||||||
|
fetch_device_values();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
system_.loop(); // does LED and checks system health, and syslog service
|
console_.loop(); // telnet/serial console
|
||||||
rxservice_.loop(); // process any incoming Rx telegrams
|
|
||||||
shower_.loop(); // check for shower on/off
|
|
||||||
dallassensor_.loop(); // read dallas sensor temperatures
|
|
||||||
publish_all_loop(); // with HA messages in parts to avoid flooding the mqtt queue
|
|
||||||
mqtt_.loop(); // sends out anything in the MQTT queue
|
|
||||||
console_.loop(); // telnet/serial console
|
|
||||||
|
|
||||||
// force a query on the EMS devices to fetch latest data at a set interval (1 min)
|
|
||||||
if ((uuid::get_uptime() - last_fetch_ > EMS_FETCH_FREQUENCY)) {
|
|
||||||
last_fetch_ = uuid::get_uptime();
|
|
||||||
fetch_device_values();
|
|
||||||
}
|
|
||||||
|
|
||||||
// delay(1); // helps telnet catch up. don't think its needed in ESP32 3.1.0
|
// delay(1); // helps telnet catch up. don't think its needed in ESP32 3.1.0
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/emsesp.h
10
src/emsesp.h
@@ -63,6 +63,10 @@
|
|||||||
#define EMSESP_JSON_SIZE_XLARGE_DYN 4096 // for very very large json docs, using DynamicJsonDocument
|
#define EMSESP_JSON_SIZE_XLARGE_DYN 4096 // for very very large json docs, using DynamicJsonDocument
|
||||||
#define EMSESP_JSON_SIZE_XXLARGE_DYN 5120 // for extra very very large json docs, using DynamicJsonDocument
|
#define EMSESP_JSON_SIZE_XXLARGE_DYN 5120 // for extra very very large json docs, using DynamicJsonDocument
|
||||||
|
|
||||||
|
// helpers for callback functions
|
||||||
|
#define MAKE_PF_CB(__f) [&](std::shared_ptr<const Telegram> t) { __f(t); } // for process function callbacks to register_telegram_type()
|
||||||
|
#define MAKE_CF_CB(__f) [&](const char * value, const int8_t id) { return __f(value, id); } // for command function callbacks to register_mqtt_cmd()
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
class Shower; // forward declaration for compiler
|
class Shower; // forward declaration for compiler
|
||||||
@@ -109,7 +113,7 @@ class EMSESP {
|
|||||||
static void show_devices(uuid::console::Shell & shell);
|
static void show_devices(uuid::console::Shell & shell);
|
||||||
static void show_ems(uuid::console::Shell & shell);
|
static void show_ems(uuid::console::Shell & shell);
|
||||||
|
|
||||||
static void init_tx();
|
static void init_uart();
|
||||||
|
|
||||||
static void incoming_telegram(uint8_t * data, const uint8_t length);
|
static void incoming_telegram(uint8_t * data, const uint8_t length);
|
||||||
|
|
||||||
@@ -187,9 +191,7 @@ class EMSESP {
|
|||||||
static WebDevicesService webDevicesService;
|
static WebDevicesService webDevicesService;
|
||||||
static WebAPIService webAPIService;
|
static WebAPIService webAPIService;
|
||||||
|
|
||||||
static uuid::log::Logger logger() {
|
static uuid::log::Logger logger();
|
||||||
return logger_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EMSESP() = delete;
|
EMSESP() = delete;
|
||||||
|
|||||||
@@ -18,19 +18,21 @@
|
|||||||
#ifndef EMSESP_EMSESP_STUB_H
|
#ifndef EMSESP_EMSESP_STUB_H
|
||||||
#define EMSESP_EMSESP_STUB_H
|
#define EMSESP_EMSESP_STUB_H
|
||||||
|
|
||||||
// forward declarator
|
|
||||||
// used to bind EMS-ESP functions to external frameworks
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "mqtt.h"
|
#include "mqtt.h"
|
||||||
#include "dallassensor.h"
|
#include "dallassensor.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
// forward declarators
|
||||||
|
// used to bind EMS-ESP functions to external frameworks
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
class EMSESP {
|
class EMSESP {
|
||||||
public:
|
public:
|
||||||
static Mqtt mqtt_;
|
static Mqtt mqtt_;
|
||||||
static System system_;
|
static System system_;
|
||||||
static DallasSensor dallassensor_;
|
static DallasSensor dallassensor_;
|
||||||
|
|
||||||
|
static uuid::log::Logger logger();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -358,7 +358,13 @@ uint16_t Helpers::atoint(const char * value) {
|
|||||||
// rounds a number to 2 decimal places
|
// rounds a number to 2 decimal places
|
||||||
// example: round2(3.14159) -> 3.14
|
// example: round2(3.14159) -> 3.14
|
||||||
double Helpers::round2(double value, const uint8_t divider) {
|
double Helpers::round2(double value, const uint8_t divider) {
|
||||||
return (int)((value / divider) * 100 + 0.5) / 100.0;
|
uint8_t div = (divider ? divider : 1); // prevent div-by-zero
|
||||||
|
|
||||||
|
if (value >= 0) {
|
||||||
|
return (int)((value / div) * 100 + 0.5) / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)((value / div) * 100 - 0.5) / 100.0; // negative values
|
||||||
}
|
}
|
||||||
|
|
||||||
// abs of a signed 32-bit integer
|
// abs of a signed 32-bit integer
|
||||||
@@ -426,6 +432,12 @@ std::string Helpers::toLower(std::string const & s) {
|
|||||||
return lc;
|
return lc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Helpers::toUpper(std::string const & s) {
|
||||||
|
std::string lc = s;
|
||||||
|
std::transform(lc.begin(), lc.end(), lc.begin(), [](unsigned char c) { return std::toupper(c); });
|
||||||
|
return lc;
|
||||||
|
}
|
||||||
|
|
||||||
// checks if we can convert a char string to a lowercase string
|
// checks if we can convert a char string to a lowercase string
|
||||||
bool Helpers::value2string(const char * v, std::string & value) {
|
bool Helpers::value2string(const char * v, std::string & value) {
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
|
|
||||||
#include "telegram.h" // for EMS_VALUE_* settings
|
#include "telegram.h" // for EMS_VALUE_* settings
|
||||||
|
|
||||||
// #define FJSON(x) x
|
#define FJSON(x) x
|
||||||
#define FJSON(x) F(x)
|
// #define FJSON(x) F(x)
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ class Helpers {
|
|||||||
static uint32_t abs(const int32_t i);
|
static uint32_t abs(const int32_t i);
|
||||||
static double round2(double value, const uint8_t divider);
|
static double round2(double value, const uint8_t divider);
|
||||||
static std::string toLower(std::string const & s);
|
static std::string toLower(std::string const & s);
|
||||||
|
static std::string toUpper(std::string const & s);
|
||||||
|
|
||||||
static bool hasValue(const uint8_t & v, const uint8_t isBool = 0);
|
static bool hasValue(const uint8_t & v, const uint8_t isBool = 0);
|
||||||
static bool hasValue(const int8_t & v);
|
static bool hasValue(const int8_t & v);
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ MAKE_PSTR_WORD(master)
|
|||||||
MAKE_PSTR_WORD(pin)
|
MAKE_PSTR_WORD(pin)
|
||||||
MAKE_PSTR_WORD(publish)
|
MAKE_PSTR_WORD(publish)
|
||||||
MAKE_PSTR_WORD(timeout)
|
MAKE_PSTR_WORD(timeout)
|
||||||
MAKE_PSTR_WORD(ethernet)
|
MAKE_PSTR_WORD(board_profile)
|
||||||
|
|
||||||
// for commands
|
// for commands
|
||||||
MAKE_PSTR_WORD(call)
|
MAKE_PSTR_WORD(call)
|
||||||
@@ -101,6 +101,7 @@ MAKE_PSTR(master_thermostat_fmt, "Master Thermostat Device ID = %s")
|
|||||||
MAKE_PSTR(host_fmt, "Host = %s")
|
MAKE_PSTR(host_fmt, "Host = %s")
|
||||||
MAKE_PSTR(port_fmt, "Port = %d")
|
MAKE_PSTR(port_fmt, "Port = %d")
|
||||||
MAKE_PSTR(hostname_fmt, "Hostname = %s")
|
MAKE_PSTR(hostname_fmt, "Hostname = %s")
|
||||||
|
MAKE_PSTR(board_profile_fmt, "Board Profile = %s")
|
||||||
MAKE_PSTR(mark_interval_fmt, "Mark interval = %lus")
|
MAKE_PSTR(mark_interval_fmt, "Mark interval = %lus")
|
||||||
MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID = %s")
|
MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID = %s")
|
||||||
MAKE_PSTR(wifi_password_fmt, "WiFi Password = %S")
|
MAKE_PSTR(wifi_password_fmt, "WiFi Password = %S")
|
||||||
@@ -187,13 +188,6 @@ MAKE_PSTR_WORD(French)
|
|||||||
MAKE_PSTR_WORD(Italian)
|
MAKE_PSTR_WORD(Italian)
|
||||||
MAKE_PSTR_WORD(high)
|
MAKE_PSTR_WORD(high)
|
||||||
MAKE_PSTR_WORD(low)
|
MAKE_PSTR_WORD(low)
|
||||||
MAKE_PSTR(internal_temperature, "internal temperature")
|
|
||||||
MAKE_PSTR(internal_setpoint, "internal setpoint")
|
|
||||||
MAKE_PSTR(external_temperature, "external temperature")
|
|
||||||
MAKE_PSTR(burner_temperature, "burner temperature")
|
|
||||||
MAKE_PSTR(WW_temperature, "WW temperature")
|
|
||||||
MAKE_PSTR(functioning_mode, "functioning mode")
|
|
||||||
MAKE_PSTR(smoke_temperature, "smoke temperature")
|
|
||||||
MAKE_PSTR_WORD(radiator)
|
MAKE_PSTR_WORD(radiator)
|
||||||
MAKE_PSTR_WORD(convector)
|
MAKE_PSTR_WORD(convector)
|
||||||
MAKE_PSTR_WORD(floor)
|
MAKE_PSTR_WORD(floor)
|
||||||
@@ -212,6 +206,13 @@ MAKE_PSTR_WORD(night)
|
|||||||
MAKE_PSTR_WORD(day)
|
MAKE_PSTR_WORD(day)
|
||||||
MAKE_PSTR_WORD(holiday)
|
MAKE_PSTR_WORD(holiday)
|
||||||
MAKE_PSTR_WORD(reduce)
|
MAKE_PSTR_WORD(reduce)
|
||||||
|
MAKE_PSTR(internal_temperature, "internal temperature")
|
||||||
|
MAKE_PSTR(internal_setpoint, "internal setpoint")
|
||||||
|
MAKE_PSTR(external_temperature, "external temperature")
|
||||||
|
MAKE_PSTR(burner_temperature, "burner temperature")
|
||||||
|
MAKE_PSTR(WW_temperature, "WW temperature")
|
||||||
|
MAKE_PSTR(functioning_mode, "functioning mode")
|
||||||
|
MAKE_PSTR(smoke_temperature, "smoke temperature")
|
||||||
|
|
||||||
// thermostat lists
|
// thermostat lists
|
||||||
MAKE_PSTR_LIST(enum_ibaMainDisplay, F_(internal_temperature), F_(internal_setpoint), F_(external_temperature), F_(burner_temperature), F_(WW_temperature), F_(functioning_mode), F_(time), F_(date), F_(smoke_temperature))
|
MAKE_PSTR_LIST(enum_ibaMainDisplay, F_(internal_temperature), F_(internal_setpoint), F_(external_temperature), F_(burner_temperature), F_(WW_temperature), F_(functioning_mode), F_(time), F_(date), F_(smoke_temperature))
|
||||||
@@ -229,12 +230,12 @@ MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter))
|
|||||||
MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto))
|
MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto))
|
||||||
MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto))
|
MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto))
|
||||||
MAKE_PSTR_LIST(enum_mode3, F_(night), F_(day), F_(auto))
|
MAKE_PSTR_LIST(enum_mode3, F_(night), F_(day), F_(auto))
|
||||||
MAKE_PSTR_LIST(enum_mode4, F_(manual), F_(auto), F_(holiday))
|
MAKE_PSTR_LIST(enum_mode4, F_(blank), F_(manual), F_(auto), F_(holiday))
|
||||||
|
|
||||||
MAKE_PSTR_LIST(enum_modetype, F_(eco), F_(comfort))
|
MAKE_PSTR_LIST(enum_modetype, F_(eco), F_(comfort))
|
||||||
MAKE_PSTR_LIST(enum_modetype2, F_(day))
|
MAKE_PSTR_LIST(enum_modetype2, F_(day))
|
||||||
MAKE_PSTR_LIST(enum_modetype3, F_(night), F_(day))
|
MAKE_PSTR_LIST(enum_modetype3, F_(night), F_(day))
|
||||||
MAKE_PSTR_LIST(enum_modetype4, F_(heat), F_(eco), F_(nofrost))
|
MAKE_PSTR_LIST(enum_modetype4, F_(blank), F_(nofrost), F_(eco), F_(heat))
|
||||||
|
|
||||||
MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor))
|
MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor))
|
||||||
|
|
||||||
|
|||||||
111
src/mqtt.cpp
111
src/mqtt.cpp
@@ -40,6 +40,7 @@ uint8_t Mqtt::bool_format_;
|
|||||||
uint8_t Mqtt::ha_climate_format_;
|
uint8_t Mqtt::ha_climate_format_;
|
||||||
bool Mqtt::ha_enabled_;
|
bool Mqtt::ha_enabled_;
|
||||||
bool Mqtt::nested_format_;
|
bool Mqtt::nested_format_;
|
||||||
|
uint8_t Mqtt::subscribe_format_;
|
||||||
|
|
||||||
std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
|
std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
|
||||||
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
||||||
@@ -64,11 +65,11 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
|
|||||||
if (!mqtt_subfunctions_.empty()) {
|
if (!mqtt_subfunctions_.empty()) {
|
||||||
for (auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
if ((mqtt_subfunction.device_type_ == device_type) && (strcmp(mqtt_subfunction.topic_.c_str(), topic.c_str()) == 0)) {
|
if ((mqtt_subfunction.device_type_ == device_type) && (strcmp(mqtt_subfunction.topic_.c_str(), topic.c_str()) == 0)) {
|
||||||
// add the function, in case its not there
|
// add the function (in case its not there) and quit because it already exists
|
||||||
if (cb) {
|
if (cb) {
|
||||||
mqtt_subfunction.mqtt_subfunction_ = cb;
|
mqtt_subfunction.mqtt_subfunction_ = cb;
|
||||||
}
|
}
|
||||||
return; // it exists, exit
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,14 +84,15 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// register in our libary with the callback function.
|
// register in our libary with the callback function.
|
||||||
// We store both the original topic and the fully-qualified one
|
// We store the original topic without base
|
||||||
mqtt_subfunctions_.emplace_back(device_type, std::move(topic), std::move(cb));
|
mqtt_subfunctions_.emplace_back(device_type, std::move(topic), std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribe to the command topic if it doesn't exist yet
|
// subscribe to the command topic if it doesn't exist yet
|
||||||
void Mqtt::register_command(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb) {
|
void Mqtt::register_command(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb, uint8_t flag) {
|
||||||
std::string cmd_topic = EMSdevice::device_type_2_device_name(device_type);
|
std::string cmd_topic = EMSdevice::device_type_2_device_name(device_type); // thermostat, boiler, etc...
|
||||||
|
|
||||||
|
// see if we have already a handler for the device type (boiler, thermostat). If not add it
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
if (!mqtt_subfunctions_.empty()) {
|
if (!mqtt_subfunctions_.empty()) {
|
||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
@@ -101,15 +103,32 @@ void Mqtt::register_command(const uint8_t device_type, const __FlashStringHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function
|
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function only (e.g. ems-esp/boiler)
|
||||||
|
LOG_DEBUG(F("Registering MQTT cmd %s with topic %s"), uuid::read_flash_string(cmd).c_str(), EMSdevice::device_type_2_device_name(device_type).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG(F("Registering MQTT cmd %s with topic %s"), uuid::read_flash_string(cmd).c_str(), EMSdevice::device_type_2_device_name(device_type).c_str());
|
// register the individual commands too (e.g. ems-esp/boiler/wwonetime)
|
||||||
|
// https://github.com/emsesp/EMS-ESP32/issues/31
|
||||||
|
std::string topic(MQTT_TOPIC_MAX_SIZE, '\0');
|
||||||
|
if (subscribe_format_ == 2 && flag == MqttSubFlag::FLAG_HC) {
|
||||||
|
topic = cmd_topic + "/hc1/" + uuid::read_flash_string(cmd);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
topic = cmd_topic + "/hc2/" + uuid::read_flash_string(cmd);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
topic = cmd_topic + "/hc3/" + uuid::read_flash_string(cmd);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
topic = cmd_topic + "/hc4/" + uuid::read_flash_string(cmd);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
} else if (subscribe_format_ && flag != MqttSubFlag::FLAG_NOSUB) {
|
||||||
|
topic = cmd_topic + "/" + uuid::read_flash_string(cmd);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
|
// subscribe to an MQTT topic, and store the associated callback function
|
||||||
|
// For generic functions not tied to a specific device
|
||||||
void Mqtt::subscribe(const std::string & topic, mqtt_subfunction_p cb) {
|
void Mqtt::subscribe(const std::string & topic, mqtt_subfunction_p cb) {
|
||||||
subscribe(0, topic, cb); // no device_id needed, if generic to EMS-ESP
|
subscribe(0, topic, cb); // no device_id needed if generic to EMS-ESP
|
||||||
}
|
}
|
||||||
|
|
||||||
// resubscribe to all MQTT topics
|
// resubscribe to all MQTT topics
|
||||||
@@ -121,11 +140,27 @@ void Mqtt::resubscribe() {
|
|||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
queue_subscribe_message(mqtt_subfunction.topic_);
|
queue_subscribe_message(mqtt_subfunction.topic_);
|
||||||
}
|
}
|
||||||
|
for (const auto & cf : Command::commands()) {
|
||||||
|
std::string topic(MQTT_TOPIC_MAX_SIZE, '\0');
|
||||||
|
if (subscribe_format_ == 2 && cf.flag_ == MqttSubFlag::FLAG_HC) {
|
||||||
|
topic = EMSdevice::device_type_2_device_name(cf.device_type_) + "/hc1/" + uuid::read_flash_string(cf.cmd_);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
topic = EMSdevice::device_type_2_device_name(cf.device_type_) + "/hc2/" + uuid::read_flash_string(cf.cmd_);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
topic = EMSdevice::device_type_2_device_name(cf.device_type_) + "/hc3/" + uuid::read_flash_string(cf.cmd_);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
topic = EMSdevice::device_type_2_device_name(cf.device_type_) + "/hc4/" + uuid::read_flash_string(cf.cmd_);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
} else if (subscribe_format_ && cf.flag_ != MqttSubFlag::FLAG_NOSUB) {
|
||||||
|
topic = EMSdevice::device_type_2_device_name(cf.device_type_) + "/" + uuid::read_flash_string(cf.cmd_);
|
||||||
|
queue_subscribe_message(topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main MQTT loop - sends out top item on publish queue
|
// Main MQTT loop - sends out top item on publish queue
|
||||||
void Mqtt::loop() {
|
void Mqtt::loop() {
|
||||||
// exit if MQTT is not enabled or if there is no WIFI
|
// exit if MQTT is not enabled or if there is no network connection
|
||||||
if (!connected()) {
|
if (!connected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -191,6 +226,16 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
|
|||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
shell.printfln(F(" %s/%s"), mqtt_base_.c_str(), mqtt_subfunction.topic_.c_str());
|
shell.printfln(F(" %s/%s"), mqtt_base_.c_str(), mqtt_subfunction.topic_.c_str());
|
||||||
}
|
}
|
||||||
|
for (const auto & cf : Command::commands()) {
|
||||||
|
if (subscribe_format_ == 2 && cf.flag_ == MqttSubFlag::FLAG_HC) {
|
||||||
|
shell.printfln(F(" %s/%s/hc1/%s"), mqtt_base_.c_str(), EMSdevice::device_type_2_device_name(cf.device_type_).c_str(), uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
shell.printfln(F(" %s/%s/hc2/%s"), mqtt_base_.c_str(), EMSdevice::device_type_2_device_name(cf.device_type_).c_str(), uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
shell.printfln(F(" %s/%s/hc3/%s"), mqtt_base_.c_str(), EMSdevice::device_type_2_device_name(cf.device_type_).c_str(), uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
shell.printfln(F(" %s/%s/hc4/%s"), mqtt_base_.c_str(), EMSdevice::device_type_2_device_name(cf.device_type_).c_str(), uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
} else if (subscribe_format_ && cf.flag_ != MqttSubFlag::FLAG_NOSUB) {
|
||||||
|
shell.printfln(F(" %s/%s/%s"), mqtt_base_.c_str(), EMSdevice::device_type_2_device_name(cf.device_type_).c_str(), uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
shell.println();
|
shell.println();
|
||||||
|
|
||||||
// show queues
|
// show queues
|
||||||
@@ -248,6 +293,12 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
char topic[100];
|
char topic[100];
|
||||||
strlcpy(topic, &fulltopic[1 + strlen(mqtt_base_.c_str())], 100);
|
strlcpy(topic, &fulltopic[1 + strlen(mqtt_base_.c_str())], 100);
|
||||||
|
|
||||||
|
// strip the topic substrings
|
||||||
|
char * topic_end = strchr(topic, '/');
|
||||||
|
if (topic_end != nullptr) {
|
||||||
|
topic_end[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// convert payload to a null-terminated char string
|
// convert payload to a null-terminated char string
|
||||||
char message[len + 2];
|
char message[len + 2];
|
||||||
strlcpy(message, payload, len + 1);
|
strlcpy(message, payload, len + 1);
|
||||||
@@ -257,7 +308,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
// see if we have this topic in our subscription list, then call its callback handler
|
// see if we have this topic in our subscription list, then call its callback handler
|
||||||
for (const auto & mf : mqtt_subfunctions_) {
|
for (const auto & mf : mqtt_subfunctions_) {
|
||||||
if (strcmp(topic, mf.topic_.c_str()) == 0) {
|
if (strcmp(topic, mf.topic_.c_str()) == 0) {
|
||||||
// if we have call back function then call it
|
// if we have callback function then call it
|
||||||
// otherwise proceed as process as a command
|
// otherwise proceed as process as a command
|
||||||
if (mf.mqtt_subfunction_) {
|
if (mf.mqtt_subfunction_) {
|
||||||
if (!(mf.mqtt_subfunction_)(message)) {
|
if (!(mf.mqtt_subfunction_)(message)) {
|
||||||
@@ -266,6 +317,28 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if it's not json, then try and extract the command from the topic name
|
||||||
|
if (message[0] != '{') {
|
||||||
|
// get topic with substrings again
|
||||||
|
strlcpy(topic, &fulltopic[1 + strlen(mqtt_base_.c_str())], 100);
|
||||||
|
char * cmd_only = strchr(topic, '/');
|
||||||
|
if (cmd_only == NULL) {
|
||||||
|
return; // invalid topic name
|
||||||
|
}
|
||||||
|
cmd_only++; // skip the /
|
||||||
|
int8_t id = -1;
|
||||||
|
// check for hcx/ prefix
|
||||||
|
if (cmd_only[0] == 'h' && cmd_only[1] == 'c' && cmd_only[3] == '/') {
|
||||||
|
id = cmd_only[2] - '0';
|
||||||
|
cmd_only += 4;
|
||||||
|
}
|
||||||
|
// LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s, id = %d"), mf.device_type_, topic, cmd_only, message, id);
|
||||||
|
if (!Command::call(mf.device_type_, cmd_only, message, id)) {
|
||||||
|
LOG_ERROR(F("No matching cmd (%s) in topic %s, id %d, or invalid data"), cmd_only, topic, id);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// It's a command then with the payload being JSON like {"cmd":"<cmd>", "data":<data>, "id":<n>}
|
// It's a command then with the payload being JSON like {"cmd":"<cmd>", "data":<data>, "id":<n>}
|
||||||
// Find the command from the json and call it directly
|
// Find the command from the json and call it directly
|
||||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||||
@@ -305,7 +378,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd_known) {
|
if (!cmd_known) {
|
||||||
LOG_ERROR(F("No matching cmd (%s), invalid data or command failed"), command);
|
LOG_ERROR(F("No matching cmd (%s) or invalid data"), command);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -388,6 +461,7 @@ void Mqtt::load_settings() {
|
|||||||
dallas_format_ = mqttSettings.dallas_format;
|
dallas_format_ = mqttSettings.dallas_format;
|
||||||
bool_format_ = mqttSettings.bool_format;
|
bool_format_ = mqttSettings.bool_format;
|
||||||
nested_format_ = mqttSettings.nested_format;
|
nested_format_ = mqttSettings.nested_format;
|
||||||
|
subscribe_format_ = mqttSettings.subscribe_format;
|
||||||
|
|
||||||
// convert to milliseconds
|
// convert to milliseconds
|
||||||
publish_time_boiler_ = mqttSettings.publish_time_boiler * 1000;
|
publish_time_boiler_ = mqttSettings.publish_time_boiler * 1000;
|
||||||
@@ -462,7 +536,7 @@ void Mqtt::start() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// create space for command buffer, to avoid heap memory fragmentation
|
// create space for command buffer, to avoid heap memory fragmentation
|
||||||
mqtt_subfunctions_.reserve(50);
|
mqtt_subfunctions_.reserve(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mqtt::set_publish_time_boiler(uint16_t publish_time) {
|
void Mqtt::set_publish_time_boiler(uint16_t publish_time) {
|
||||||
@@ -515,7 +589,7 @@ bool Mqtt::get_publish_onchange(uint8_t device_type) {
|
|||||||
// MQTT onConnect - when an MQTT connect is established
|
// MQTT onConnect - when an MQTT connect is established
|
||||||
// send out some inital MQTT messages
|
// send out some inital MQTT messages
|
||||||
void Mqtt::on_connect() {
|
void Mqtt::on_connect() {
|
||||||
if (connecting_) { // prevent duplicating connections
|
if (connecting_) { // prevent duplicated connections
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +611,11 @@ void Mqtt::on_connect() {
|
|||||||
|
|
||||||
doc["version"] = EMSESP_APP_VERSION;
|
doc["version"] = EMSESP_APP_VERSION;
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
doc["ip"] = WiFi.localIP().toString();
|
if (EMSESP::system_.ethernet_connected()) {
|
||||||
|
doc["ip"] = ETH.localIP().toString();
|
||||||
|
} else {
|
||||||
|
doc["ip"] = WiFi.localIP().toString();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
publish(F_(info), doc.as<JsonObject>());
|
publish(F_(info), doc.as<JsonObject>());
|
||||||
|
|
||||||
@@ -550,7 +628,6 @@ void Mqtt::on_connect() {
|
|||||||
EMSESP::shower_.send_mqtt_stat(false); // Send shower_activated as false
|
EMSESP::shower_.send_mqtt_stat(false); // Send shower_activated as false
|
||||||
EMSESP::system_.send_heartbeat(); // send heatbeat
|
EMSESP::system_.send_heartbeat(); // send heatbeat
|
||||||
|
|
||||||
// } else {
|
|
||||||
if (connectcount_ > 1) {
|
if (connectcount_ > 1) {
|
||||||
// we doing a re-connect from a TCP break
|
// we doing a re-connect from a TCP break
|
||||||
// only re-subscribe again to all MQTT topics
|
// only re-subscribe again to all MQTT topics
|
||||||
@@ -599,7 +676,7 @@ void Mqtt::ha_status() {
|
|||||||
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
// create the sensors
|
// create the sensors
|
||||||
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Wifi strength"), EMSdevice::DeviceType::SYSTEM, F("rssi"));
|
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("WiFi strength"), EMSdevice::DeviceType::SYSTEM, F("rssi"));
|
||||||
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Uptime"), EMSdevice::DeviceType::SYSTEM, F("uptime"));
|
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Uptime"), EMSdevice::DeviceType::SYSTEM, F("uptime"));
|
||||||
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Uptime (sec)"), EMSdevice::DeviceType::SYSTEM, F("uptime_sec"));
|
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Uptime (sec)"), EMSdevice::DeviceType::SYSTEM, F("uptime_sec"));
|
||||||
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Free heap memory"), EMSdevice::DeviceType::SYSTEM, F("freemem"));
|
publish_mqtt_ha_sensor(DeviceValueType::INT, DeviceValueTAG::TAG_HEARTBEAT, F("Free heap memory"), EMSdevice::DeviceType::SYSTEM, F("freemem"));
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class Mqtt {
|
|||||||
static void publish_ha(const __FlashStringHelper * topic, const JsonObject & payload);
|
static void publish_ha(const __FlashStringHelper * topic, const JsonObject & payload);
|
||||||
|
|
||||||
static void publish_mqtt_ha_sensor(uint8_t type, uint8_t tag, const __FlashStringHelper * name, const uint8_t device_type, const __FlashStringHelper * entity, const uint8_t uom = 0);
|
static void publish_mqtt_ha_sensor(uint8_t type, uint8_t tag, const __FlashStringHelper * name, const uint8_t device_type, const __FlashStringHelper * entity, const uint8_t uom = 0);
|
||||||
static void register_command(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb);
|
static void register_command(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb, uint8_t tag = 0);
|
||||||
|
|
||||||
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
||||||
static void show_mqtt(uuid::console::Shell & shell);
|
static void show_mqtt(uuid::console::Shell & shell);
|
||||||
@@ -275,6 +275,7 @@ class Mqtt {
|
|||||||
static uint8_t ha_climate_format_;
|
static uint8_t ha_climate_format_;
|
||||||
static bool ha_enabled_;
|
static bool ha_enabled_;
|
||||||
static bool nested_format_;
|
static bool nested_format_;
|
||||||
|
static uint8_t subscribe_format_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ void Shower::send_mqtt_stat(bool state, bool force) {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp");
|
ids.add("ems-esp");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/%s/shower_active/config"), Mqtt::base().c_str());
|
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/%s/shower_active/config"), Mqtt::base().c_str());
|
||||||
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
}
|
}
|
||||||
|
|||||||
251
src/system.cpp
251
src/system.cpp
@@ -39,7 +39,7 @@ PButton System::myPButton_;
|
|||||||
// value: true = HIGH, false = LOW
|
// value: true = HIGH, false = LOW
|
||||||
// e.g. http://ems-esp/api?device=system&cmd=pin&data=1&id=2
|
// e.g. http://ems-esp/api?device=system&cmd=pin&data=1&id=2
|
||||||
bool System::command_pin(const char * value, const int8_t id) {
|
bool System::command_pin(const char * value, const int8_t id) {
|
||||||
if (id < 0) {
|
if (!is_valid_gpio(id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,19 +119,29 @@ void System::format(uuid::console::Shell & shell) {
|
|||||||
System::restart();
|
System::restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::syslog_start() {
|
||||||
|
if (syslog_enabled_) {
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
|
syslog_.start();
|
||||||
|
#endif
|
||||||
|
EMSESP::logger().info(F("Starting Syslog"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void System::syslog_init(bool refresh) {
|
void System::syslog_init(bool refresh) {
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
get_settings();
|
get_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
// check for empty hostname
|
// check for empty or invalid hostname
|
||||||
IPAddress addr;
|
IPAddress addr;
|
||||||
if (!addr.fromString(syslog_host_.c_str())) {
|
if (!addr.fromString(syslog_host_.c_str())) {
|
||||||
syslog_enabled_ = false;
|
syslog_enabled_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in case service is still running, this flushes the queue - https://github.com/emsesp/EMS-ESP/issues/496
|
// in case service is still running, this flushes the queue
|
||||||
|
// https://github.com/emsesp/EMS-ESP/issues/496
|
||||||
if (!syslog_enabled_) {
|
if (!syslog_enabled_) {
|
||||||
syslog_.log_level((uuid::log::Level)-1);
|
syslog_.log_level((uuid::log::Level)-1);
|
||||||
syslog_.mark_interval(0);
|
syslog_.mark_interval(0);
|
||||||
@@ -140,26 +150,23 @@ void System::syslog_init(bool refresh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start & configure syslog
|
// start & configure syslog
|
||||||
syslog_.start();
|
|
||||||
syslog_.log_level((uuid::log::Level)syslog_level_);
|
syslog_.log_level((uuid::log::Level)syslog_level_);
|
||||||
syslog_.mark_interval(syslog_mark_interval_);
|
syslog_.mark_interval(syslog_mark_interval_);
|
||||||
syslog_.destination(addr, syslog_port_);
|
syslog_.destination(addr, syslog_port_);
|
||||||
syslog_.hostname(hostname_.c_str());
|
syslog_.hostname(hostname().c_str());
|
||||||
|
|
||||||
EMSESP::logger().info(F("Syslog started"));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// read all the settings from the config files and store locally
|
// read all the settings from the config files and store locally
|
||||||
void System::get_settings() {
|
void System::get_settings() {
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
// BUTTON
|
// Button
|
||||||
pbutton_gpio_ = settings.pbutton_gpio;
|
pbutton_gpio_ = settings.pbutton_gpio;
|
||||||
|
|
||||||
// ADC
|
// ADC
|
||||||
analog_enabled_ = settings.analog_enabled;
|
analog_enabled_ = settings.analog_enabled;
|
||||||
|
|
||||||
// SYSLOG
|
// Syslog
|
||||||
syslog_enabled_ = settings.syslog_enabled;
|
syslog_enabled_ = settings.syslog_enabled;
|
||||||
syslog_level_ = settings.syslog_level;
|
syslog_level_ = settings.syslog_level;
|
||||||
syslog_mark_interval_ = settings.syslog_mark_interval;
|
syslog_mark_interval_ = settings.syslog_mark_interval;
|
||||||
@@ -169,12 +176,9 @@ void System::get_settings() {
|
|||||||
// LED
|
// LED
|
||||||
hide_led_ = settings.hide_led;
|
hide_led_ = settings.hide_led;
|
||||||
led_gpio_ = settings.led_gpio;
|
led_gpio_ = settings.led_gpio;
|
||||||
});
|
|
||||||
|
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
// Board profile
|
||||||
hostname(networkSettings.hostname.c_str());
|
board_profile_ = settings.board_profile;
|
||||||
LOG_INFO(F("System %s booted (EMS-ESP version %s)"), networkSettings.hostname.c_str(), EMSESP_APP_VERSION); // print boot message
|
|
||||||
ethernet_profile_ = networkSettings.ethernet_profile;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,10 +205,22 @@ void System::wifi_tweak() {
|
|||||||
bool s1 = WiFi.getSleep();
|
bool s1 = WiFi.getSleep();
|
||||||
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
|
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
|
||||||
bool s2 = WiFi.getSleep();
|
bool s2 = WiFi.getSleep();
|
||||||
LOG_INFO(F("Adjusting Wifi - Tx power %d->%d, Sleep %d->%d"), p1, p2, s1, s2);
|
LOG_DEBUG(F("Adjusting WiFi - Tx power %d->%d, Sleep %d->%d"), p1, p2, s1, s2);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for valid ESP32 pins. This is very dependent on which ESP32 board is being used.
|
||||||
|
// Typically you can't use 1, 6-11, 12, 14, 15, 20, 24, 28-31 and 40+
|
||||||
|
// we allow 0 as it has a special function on the NodeMCU apparently
|
||||||
|
// See https://diyprojects.io/esp32-how-to-use-gpio-digital-io-arduino-code/#.YFpVEq9KhjG
|
||||||
|
// and https://nodemcu.readthedocs.io/en/dev-esp32/modules/gpio/
|
||||||
|
bool System::is_valid_gpio(uint8_t pin) {
|
||||||
|
if ((pin == 1) || (pin >= 6 && pin <= 12) || (pin >= 14 && pin <= 15) || (pin == 20) || (pin == 24) || (pin >= 28 && pin <= 31) || (pin > 40)) {
|
||||||
|
return false; // bad pin
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// first call. Sets memory and starts up the UART Serial bridge
|
// first call. Sets memory and starts up the UART Serial bridge
|
||||||
void System::start(uint32_t heap_start) {
|
void System::start(uint32_t heap_start) {
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
@@ -219,14 +235,19 @@ void System::start(uint32_t heap_start) {
|
|||||||
// load in all the settings first
|
// load in all the settings first
|
||||||
get_settings();
|
get_settings();
|
||||||
|
|
||||||
|
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||||
|
hostname(networkSettings.hostname.c_str()); // sets the hostname
|
||||||
|
LOG_INFO(F("System name: %s"), hostname().c_str());
|
||||||
|
});
|
||||||
|
|
||||||
commands_init(); // console & api commands
|
commands_init(); // console & api commands
|
||||||
led_init(false); // init LED
|
led_init(false); // init LED
|
||||||
adc_init(false); // analog ADC
|
adc_init(false); // analog ADC
|
||||||
syslog_init(false); // init SysLog
|
|
||||||
button_init(false); // the special button
|
button_init(false); // the special button
|
||||||
network_init(false); // network
|
network_init(false); // network
|
||||||
|
syslog_init(false); // init SysLog
|
||||||
|
|
||||||
EMSESP::init_tx(); // start UART
|
EMSESP::init_uart(); // start UART
|
||||||
}
|
}
|
||||||
|
|
||||||
// adc and bluetooth
|
// adc and bluetooth
|
||||||
@@ -237,12 +258,14 @@ void System::adc_init(bool refresh) {
|
|||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
// setCpuFrequencyMhz(160); // default is 240
|
// setCpuFrequencyMhz(160); // default is 240
|
||||||
|
|
||||||
// disable bluetooth
|
// disable bluetooth & ADC
|
||||||
|
/*
|
||||||
btStop();
|
btStop();
|
||||||
esp_bt_controller_disable();
|
esp_bt_controller_disable();
|
||||||
if (!analog_enabled_) {
|
if (!analog_enabled_) {
|
||||||
adc_power_off(); // turn off ADC to save power if not needed
|
adc_power_release(); // turn off ADC to save power if not needed
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,19 +306,20 @@ void System::button_init(bool refresh) {
|
|||||||
get_settings();
|
get_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow 0 for Boot-button on NodeMCU-32s?
|
if (is_valid_gpio(pbutton_gpio_)) {
|
||||||
// if (pbutton_gpio_) {
|
if (!myPButton_.init(pbutton_gpio_, HIGH)) {
|
||||||
if (!myPButton_.init(pbutton_gpio_, HIGH)) {
|
LOG_INFO(F("Multi-functional button not detected"));
|
||||||
LOG_INFO(F("External multi-functional button not detected"));
|
} else {
|
||||||
|
LOG_INFO(F("Multi-functional button enabled"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(F("External multi-functional button enabled"));
|
LOG_WARNING(F("Invalid button GPIO. Check config."));
|
||||||
}
|
}
|
||||||
|
|
||||||
myPButton_.onClick(BUTTON_Debounce, button_OnClick);
|
myPButton_.onClick(BUTTON_Debounce, button_OnClick);
|
||||||
myPButton_.onDblClick(BUTTON_DblClickDelay, button_OnDblClick);
|
myPButton_.onDblClick(BUTTON_DblClickDelay, button_OnDblClick);
|
||||||
myPButton_.onLongPress(BUTTON_LongPressDelay, button_OnLongPress);
|
myPButton_.onLongPress(BUTTON_LongPressDelay, button_OnLongPress);
|
||||||
myPButton_.onVLongPress(BUTTON_VLongPressDelay, button_OnVLongPress);
|
myPButton_.onVLongPress(BUTTON_VLongPressDelay, button_OnVLongPress);
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the LED to on or off when in normal operating mode
|
// set the LED to on or off when in normal operating mode
|
||||||
@@ -304,9 +328,9 @@ void System::led_init(bool refresh) {
|
|||||||
get_settings();
|
get_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (led_gpio_) {
|
if ((led_gpio_ != 0) && is_valid_gpio(led_gpio_)) {
|
||||||
pinMode(led_gpio_, OUTPUT); // 0 means disabled
|
pinMode(led_gpio_, OUTPUT); // 0 means disabled
|
||||||
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); // LED on, for ever
|
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,9 +404,12 @@ void System::send_heartbeat() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t rssi = wifi_quality();
|
int8_t rssi;
|
||||||
if (rssi == -1) {
|
if (!ethernet_connected_) {
|
||||||
return;
|
rssi = wifi_quality();
|
||||||
|
if (rssi == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||||
@@ -396,11 +423,13 @@ void System::send_heartbeat() {
|
|||||||
doc["status"] = FJSON("disconnected");
|
doc["status"] = FJSON("disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
doc["rssi"] = rssi;
|
if (!ethernet_connected_) {
|
||||||
|
doc["rssi"] = rssi;
|
||||||
|
}
|
||||||
doc["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
|
doc["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
|
||||||
doc["uptime_sec"] = uuid::get_uptime_sec();
|
doc["uptime_sec"] = uuid::get_uptime_sec();
|
||||||
doc["mqttfails"] = Mqtt::publish_fails();
|
doc["mqttfails"] = Mqtt::publish_fails();
|
||||||
doc["rxsent"] = EMSESP::rxservice_.telegram_count();
|
doc["rxreceived"] = EMSESP::rxservice_.telegram_count();
|
||||||
doc["rxfails"] = EMSESP::rxservice_.telegram_error_count();
|
doc["rxfails"] = EMSESP::rxservice_.telegram_error_count();
|
||||||
doc["txread"] = EMSESP::txservice_.telegram_read_count();
|
doc["txread"] = EMSESP::txservice_.telegram_read_count();
|
||||||
doc["txwrite"] = EMSESP::txservice_.telegram_write_count();
|
doc["txwrite"] = EMSESP::txservice_.telegram_write_count();
|
||||||
@@ -452,9 +481,12 @@ void System::network_init(bool refresh) {
|
|||||||
get_settings();
|
get_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check ethernet profile
|
last_system_check_ = 0; // force the LED to go from fast flash to pulse
|
||||||
|
send_heartbeat();
|
||||||
|
|
||||||
|
// check board profile for those which use ethernet
|
||||||
// ethernet uses lots of additional memory so we only start it when it's explicitly set in the config
|
// ethernet uses lots of additional memory so we only start it when it's explicitly set in the config
|
||||||
if (ethernet_profile_ == 0) {
|
if (!board_profile_.equals("E32") && !board_profile_.equals("TLK110") && !board_profile_.equals("LAN8720") && !board_profile_.equals("OLIMEX")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,45 +497,36 @@ void System::network_init(bool refresh) {
|
|||||||
eth_phy_type_t type; // Type of the Ethernet PHY (LAN8720 or TLK110)
|
eth_phy_type_t type; // Type of the Ethernet PHY (LAN8720 or TLK110)
|
||||||
eth_clock_mode_t clock_mode; // ETH_CLOCK_GPIO0_IN or ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT for 50Hz inverted clock
|
eth_clock_mode_t clock_mode; // ETH_CLOCK_GPIO0_IN or ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT for 50Hz inverted clock
|
||||||
|
|
||||||
if (ethernet_profile_ == 1) {
|
if (board_profile_.equals("E32") || board_profile_.equals("LAN8720")) {
|
||||||
// LAN8720
|
// BBQKees Gateway E32 (LAN8720)
|
||||||
|
phy_addr = 1;
|
||||||
|
power = 16;
|
||||||
|
mdc = 23;
|
||||||
|
mdio = 18;
|
||||||
|
type = ETH_PHY_LAN8720;
|
||||||
|
clock_mode = ETH_CLOCK_GPIO0_IN;
|
||||||
|
} else if (board_profile_.equals("OLIMEX")) {
|
||||||
|
// Olimex ESP32-EVB (LAN8720)
|
||||||
phy_addr = 0;
|
phy_addr = 0;
|
||||||
power = -1;
|
power = -1;
|
||||||
mdc = 23;
|
mdc = 23;
|
||||||
mdio = 18;
|
mdio = 18;
|
||||||
type = ETH_PHY_LAN8720;
|
type = ETH_PHY_LAN8720;
|
||||||
clock_mode = ETH_CLOCK_GPIO0_IN;
|
clock_mode = ETH_CLOCK_GPIO0_IN;
|
||||||
} else if (ethernet_profile_ == 2) {
|
} else if (board_profile_.equals("TLK110")) {
|
||||||
// TLK110
|
// Ethernet (TLK110)
|
||||||
phy_addr = 31;
|
phy_addr = 31;
|
||||||
power = -1;
|
power = -1;
|
||||||
mdc = 23;
|
mdc = 23;
|
||||||
mdio = 18;
|
mdio = 18;
|
||||||
type = ETH_PHY_TLK110;
|
type = ETH_PHY_TLK110;
|
||||||
clock_mode = ETH_CLOCK_GPIO0_IN;
|
clock_mode = ETH_CLOCK_GPIO0_IN;
|
||||||
|
} else {
|
||||||
|
return; // invalid combi
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
// bool have_ethernet = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
|
||||||
if (ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode)) {
|
(void)ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
|
||||||
// disable ssid and AP when using Ethernet
|
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->update(
|
|
||||||
[&](NetworkSettings & settings) {
|
|
||||||
settings.ssid == ""; // remove SSID
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
},
|
|
||||||
"local");
|
|
||||||
|
|
||||||
EMSESP::esp8266React.getAPSettingsService()->update(
|
|
||||||
[&](APSettings & settings) {
|
|
||||||
settings.provisionMode = AP_MODE_NEVER;
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
},
|
|
||||||
"local");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
last_system_check_ = 0; // force the LED to go from fast flash to pulse
|
|
||||||
send_heartbeat();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check health of system, done every few seconds
|
// check health of system, done every few seconds
|
||||||
@@ -512,7 +535,7 @@ void System::system_check() {
|
|||||||
last_system_check_ = uuid::get_uptime();
|
last_system_check_ = uuid::get_uptime();
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (!ethernet_connected() && (WiFi.status() != WL_CONNECTED)) {
|
||||||
set_led_speed(LED_WARNING_BLINK_FAST);
|
set_led_speed(LED_WARNING_BLINK_FAST);
|
||||||
system_healthy_ = false;
|
system_healthy_ = false;
|
||||||
return;
|
return;
|
||||||
@@ -532,7 +555,7 @@ void System::system_check() {
|
|||||||
system_healthy_ = true;
|
system_healthy_ = true;
|
||||||
send_heartbeat();
|
send_heartbeat();
|
||||||
if (led_gpio_) {
|
if (led_gpio_) {
|
||||||
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); // LED on, for ever
|
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -541,8 +564,9 @@ void System::system_check() {
|
|||||||
|
|
||||||
// commands - takes static function pointers
|
// commands - takes static function pointers
|
||||||
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
|
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
|
||||||
|
// no individual subscribe for pin command because id is needed
|
||||||
void System::commands_init() {
|
void System::commands_init() {
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin, MqttSubFlag::FLAG_NOSUB);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(publish), System::command_publish);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(publish), System::command_publish);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch);
|
||||||
@@ -751,7 +775,7 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
CommandFlags::ADMIN,
|
CommandFlags::ADMIN,
|
||||||
flash_string_vector{F_(set), F_(hostname)},
|
flash_string_vector{F_(set), F_(hostname)},
|
||||||
flash_string_vector{F_(name_mandatory)},
|
flash_string_vector{F_(name_mandatory)},
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
shell.println("The network connection will be reset...");
|
shell.println("The network connection will be reset...");
|
||||||
Shell::loop_all();
|
Shell::loop_all();
|
||||||
delay(1000); // wait a second
|
delay(1000); // wait a second
|
||||||
@@ -795,41 +819,39 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
||||||
ShellContext::SYSTEM,
|
CommandFlags::ADMIN,
|
||||||
CommandFlags::ADMIN,
|
flash_string_vector{F_(set), F_(board_profile)},
|
||||||
flash_string_vector{F_(set), F_(ethernet)},
|
flash_string_vector{F_(name_mandatory)},
|
||||||
flash_string_vector{F_(n_mandatory)},
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
std::vector<uint8_t> data; // led, dallas, rx, tx, button
|
||||||
uint8_t n = Helpers::hextoint(arguments.front().c_str());
|
std::string board_profile = Helpers::toUpper(arguments.front());
|
||||||
if (n <= 2) {
|
if (!load_board_profile(data, board_profile)) {
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->update(
|
shell.println(F("Invalid board profile"));
|
||||||
[&](NetworkSettings & networkSettings) {
|
return;
|
||||||
networkSettings.ethernet_profile = n;
|
}
|
||||||
shell.printfln(F_(ethernet_option_fmt), networkSettings.ethernet_profile);
|
EMSESP::webSettingsService.update(
|
||||||
return StateUpdateResult::CHANGED;
|
[&](WebSettings & settings) {
|
||||||
},
|
settings.board_profile = board_profile.c_str();
|
||||||
"local");
|
settings.led_gpio = data[0];
|
||||||
EMSESP::system_.network_init(true);
|
settings.dallas_gpio = data[1];
|
||||||
} else {
|
settings.rx_gpio = data[2];
|
||||||
shell.println(F("Must be 0, 1 or 2"));
|
settings.tx_gpio = data[3];
|
||||||
}
|
settings.pbutton_gpio = data[4];
|
||||||
},
|
return StateUpdateResult::CHANGED;
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
},
|
||||||
return std::vector<std::string>{read_flash_string(F("0")), read_flash_string(F("1")), read_flash_string(F("2"))};
|
"local");
|
||||||
});
|
shell.printfln("Loaded board profile %s (%d,%d,%d,%d,%d)", board_profile.c_str(), data[0], data[1], data[2], data[3], data[4]);
|
||||||
|
EMSESP::system_.network_init(true);
|
||||||
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::USER, flash_string_vector{F_(set)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::USER, flash_string_vector{F_(set)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(hostname_fmt), networkSettings.hostname.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.hostname.c_str());
|
shell.printfln(F_(hostname_fmt), networkSettings.hostname.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.hostname.c_str());
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(wifi_ssid_fmt), networkSettings.ssid.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.ssid.c_str());
|
shell.printfln(F_(wifi_ssid_fmt), networkSettings.ssid.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.ssid.c_str());
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(wifi_password_fmt), networkSettings.ssid.isEmpty() ? F_(unset) : F_(asterisks));
|
shell.printfln(F_(wifi_password_fmt), networkSettings.ssid.isEmpty() ? F_(unset) : F_(asterisks));
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(ethernet_option_fmt), networkSettings.ethernet_profile);
|
|
||||||
});
|
});
|
||||||
|
EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str()); });
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::ADMIN, flash_string_vector{F_(show), F_(users)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::ADMIN, flash_string_vector{F_(show), F_(users)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
@@ -850,8 +872,13 @@ bool System::check_upgrade() {
|
|||||||
// e.g. http://ems-esp/api?device=system&cmd=settings
|
// e.g. http://ems-esp/api?device=system&cmd=settings
|
||||||
// value and id are ignored
|
// value and id are ignored
|
||||||
bool System::command_settings(const char * value, const int8_t id, JsonObject & json) {
|
bool System::command_settings(const char * value, const int8_t id, JsonObject & json) {
|
||||||
|
JsonObject node;
|
||||||
|
|
||||||
|
node = json.createNestedObject("System");
|
||||||
|
node["version"] = EMSESP_APP_VERSION;
|
||||||
|
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & settings) {
|
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & settings) {
|
||||||
JsonObject node = json.createNestedObject("WIFI");
|
node = json.createNestedObject("WIFI");
|
||||||
node["ssid"] = settings.ssid;
|
node["ssid"] = settings.ssid;
|
||||||
node["hostname"] = settings.hostname;
|
node["hostname"] = settings.hostname;
|
||||||
node["static_ip_config"] = settings.staticIPConfig;
|
node["static_ip_config"] = settings.staticIPConfig;
|
||||||
@@ -864,7 +891,7 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
EMSESP::esp8266React.getAPSettingsService()->read([&](APSettings & settings) {
|
EMSESP::esp8266React.getAPSettingsService()->read([&](APSettings & settings) {
|
||||||
JsonObject node = json.createNestedObject("AP");
|
node = json.createNestedObject("AP");
|
||||||
node["provision_mode"] = settings.provisionMode;
|
node["provision_mode"] = settings.provisionMode;
|
||||||
node["ssid"] = settings.ssid;
|
node["ssid"] = settings.ssid;
|
||||||
node["local_ip"] = settings.localIP.toString();
|
node["local_ip"] = settings.localIP.toString();
|
||||||
@@ -874,7 +901,7 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
||||||
JsonObject node = json.createNestedObject("MQTT");
|
node = json.createNestedObject("MQTT");
|
||||||
node["enabled"] = settings.enabled;
|
node["enabled"] = settings.enabled;
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
node["host"] = settings.host;
|
node["host"] = settings.host;
|
||||||
@@ -900,7 +927,7 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) {
|
EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) {
|
||||||
JsonObject node = json.createNestedObject("NTP");
|
node = json.createNestedObject("NTP");
|
||||||
node["enabled"] = settings.enabled;
|
node["enabled"] = settings.enabled;
|
||||||
node["server"] = settings.server;
|
node["server"] = settings.server;
|
||||||
node["tz_label"] = settings.tzLabel;
|
node["tz_label"] = settings.tzLabel;
|
||||||
@@ -908,14 +935,14 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
});
|
});
|
||||||
|
|
||||||
EMSESP::esp8266React.getOTASettingsService()->read([&](OTASettings & settings) {
|
EMSESP::esp8266React.getOTASettingsService()->read([&](OTASettings & settings) {
|
||||||
JsonObject node = json.createNestedObject("OTA");
|
node = json.createNestedObject("OTA");
|
||||||
node["enabled"] = settings.enabled;
|
node["enabled"] = settings.enabled;
|
||||||
node["port"] = settings.port;
|
node["port"] = settings.port;
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
JsonObject node = json.createNestedObject("Settings");
|
node = json.createNestedObject("Settings");
|
||||||
node["tx_mode"] = settings.tx_mode;
|
node["tx_mode"] = settings.tx_mode;
|
||||||
node["ems_bus_id"] = settings.ems_bus_id;
|
node["ems_bus_id"] = settings.ems_bus_id;
|
||||||
node["syslog_enabled"] = settings.syslog_enabled;
|
node["syslog_enabled"] = settings.syslog_enabled;
|
||||||
@@ -935,6 +962,7 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
node["api_enabled"] = settings.api_enabled;
|
node["api_enabled"] = settings.api_enabled;
|
||||||
node["analog_enabled"] = settings.analog_enabled;
|
node["analog_enabled"] = settings.analog_enabled;
|
||||||
node["pbutton_gpio"] = settings.pbutton_gpio;
|
node["pbutton_gpio"] = settings.pbutton_gpio;
|
||||||
|
node["board_profile"] = settings.board_profile;
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1004,5 +1032,32 @@ bool System::command_test(const char * value, const int8_t id) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// takes a board profile and populates a data array with GPIO configurations
|
||||||
|
// data = led, dallas, rx, tx, button
|
||||||
|
// returns false if profile is not found
|
||||||
|
bool System::load_board_profile(std::vector<uint8_t> & data, const std::string & board_profile) {
|
||||||
|
if (board_profile == "S32") {
|
||||||
|
data = {2, 3, 23, 5, 0}; // BBQKees Gateway S32
|
||||||
|
} else if (board_profile == "E32") {
|
||||||
|
data = {2, 4, 5, 17, 33}; // BBQKees Gateway E32
|
||||||
|
} else if (board_profile == "MT-ET") {
|
||||||
|
data = {2, 18, 23, 5, 0}; // MT-ET Live D1 Mini
|
||||||
|
} else if (board_profile == "NODEMCU") {
|
||||||
|
data = {2, 18, 23, 5, 0}; // NodeMCU 32S
|
||||||
|
} else if (board_profile == "LOLIN") {
|
||||||
|
data = {2, 18, 17, 16, 0}; // Lolin D32
|
||||||
|
} else if (board_profile == "OLIMEX") {
|
||||||
|
data = {0, 0, 36, 4, 34}; // Olimex ESP32-EVB (uses U1TXD/U1RXD/BUTTON, no LED or Dallas)
|
||||||
|
} else if (board_profile == "TLK110") {
|
||||||
|
data = {2, 4, 5, 17, 33}; // Generic Ethernet (TLK110)
|
||||||
|
} else if (board_profile == "LAN8720") {
|
||||||
|
data = {2, 4, 5, 17, 33}; // Generic Ethernet (LAN8720)
|
||||||
|
} else {
|
||||||
|
data = {EMSESP_DEFAULT_LED_GPIO, EMSESP_DEFAULT_DALLAS_GPIO, EMSESP_DEFAULT_RX_GPIO, EMSESP_DEFAULT_TX_GPIO, EMSESP_DEFAULT_PBUTTON_GPIO};
|
||||||
|
return (board_profile == "CUSTOM");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
33
src/system.h
33
src/system.h
@@ -66,6 +66,9 @@ class System {
|
|||||||
void show_mem(const char * note);
|
void show_mem(const char * note);
|
||||||
void get_settings();
|
void get_settings();
|
||||||
void wifi_tweak();
|
void wifi_tweak();
|
||||||
|
void syslog_start();
|
||||||
|
bool check_upgrade();
|
||||||
|
void send_heartbeat();
|
||||||
|
|
||||||
void led_init(bool refresh);
|
void led_init(bool refresh);
|
||||||
void syslog_init(bool refresh);
|
void syslog_init(bool refresh);
|
||||||
@@ -74,8 +77,8 @@ class System {
|
|||||||
void button_init(bool refresh);
|
void button_init(bool refresh);
|
||||||
void commands_init();
|
void commands_init();
|
||||||
|
|
||||||
bool check_upgrade();
|
static bool is_valid_gpio(uint8_t pin);
|
||||||
void send_heartbeat();
|
static bool load_board_profile(std::vector<uint8_t> & data, const std::string & board_profile);
|
||||||
|
|
||||||
std::string hostname() {
|
std::string hostname() {
|
||||||
return hostname_;
|
return hostname_;
|
||||||
@@ -93,6 +96,14 @@ class System {
|
|||||||
ethernet_connected_ = b;
|
ethernet_connected_ = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool network_connected() {
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
|
return (ethernet_connected_ || WiFi.isConnected());
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
static uint32_t heap_start_;
|
static uint32_t heap_start_;
|
||||||
@@ -113,7 +124,7 @@ class System {
|
|||||||
static constexpr uint32_t LED_WARNING_BLINK_FAST = 100; // flash quickly for boot up sequence
|
static constexpr uint32_t LED_WARNING_BLINK_FAST = 100; // flash quickly for boot up sequence
|
||||||
static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
||||||
static constexpr uint32_t SYSTEM_MEASURE_ANALOG_INTERVAL = 500;
|
static constexpr uint32_t SYSTEM_MEASURE_ANALOG_INTERVAL = 500;
|
||||||
static constexpr uint8_t LED_ON = LOW; // internal LED
|
static constexpr uint8_t LED_ON = HIGH; // LED
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
static uuid::syslog::SyslogService syslog_;
|
static uuid::syslog::SyslogService syslog_;
|
||||||
@@ -129,21 +140,21 @@ class System {
|
|||||||
void wifi_reconnect();
|
void wifi_reconnect();
|
||||||
int8_t wifi_quality();
|
int8_t wifi_quality();
|
||||||
|
|
||||||
bool system_healthy_ = false;
|
bool system_healthy_ = false;
|
||||||
uint32_t led_flash_speed_ = LED_WARNING_BLINK_FAST; // default boot flashes quickly
|
uint32_t led_flash_speed_ = LED_WARNING_BLINK_FAST; // default boot flashes quickly
|
||||||
uint32_t last_heartbeat_ = 0;
|
uint32_t last_heartbeat_ = 0;
|
||||||
uint32_t last_system_check_ = 0;
|
uint32_t last_system_check_ = 0;
|
||||||
bool upload_status_ = false; // true if we're in the middle of a OTA firmware upload
|
bool upload_status_ = false; // true if we're in the middle of a OTA firmware upload
|
||||||
bool ethernet_connected_;
|
bool ethernet_connected_ = false;
|
||||||
uint16_t analog_;
|
uint16_t analog_;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
std::string hostname_;
|
std::string hostname_ = "ems-esp";
|
||||||
bool hide_led_;
|
bool hide_led_;
|
||||||
uint8_t led_gpio_;
|
uint8_t led_gpio_;
|
||||||
bool syslog_enabled_;
|
bool syslog_enabled_;
|
||||||
bool analog_enabled_;
|
bool analog_enabled_;
|
||||||
uint8_t ethernet_profile_;
|
String board_profile_;
|
||||||
uint8_t pbutton_gpio_;
|
uint8_t pbutton_gpio_;
|
||||||
int8_t syslog_level_;
|
int8_t syslog_level_;
|
||||||
uint32_t syslog_mark_interval_;
|
uint32_t syslog_mark_interval_;
|
||||||
|
|||||||
@@ -22,19 +22,15 @@
|
|||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
// CRC lookup table with poly 12 for faster checking
|
// CRC lookup table with poly 12 for faster checking
|
||||||
const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26,
|
const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38,
|
||||||
0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E,
|
0x3A, 0x3C, 0x3E, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72,
|
||||||
0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76,
|
0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E, 0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC,
|
||||||
0x78, 0x7A, 0x7C, 0x7E, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E,
|
0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE, 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, 0xE0, 0xE2, 0xE4, 0xE6,
|
||||||
0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE, 0xC0, 0xC2, 0xC4, 0xC6,
|
0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE, 0x19, 0x1B, 0x1D, 0x1F, 0x11, 0x13, 0x15, 0x17, 0x09, 0x0B, 0x0D, 0x0F, 0x01, 0x03, 0x05, 0x07, 0x39,
|
||||||
0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
|
0x3B, 0x3D, 0x3F, 0x31, 0x33, 0x35, 0x37, 0x29, 0x2B, 0x2D, 0x2F, 0x21, 0x23, 0x25, 0x27, 0x59, 0x5B, 0x5D, 0x5F, 0x51, 0x53, 0x55, 0x57, 0x49, 0x4B, 0x4D, 0x4F, 0x41, 0x43,
|
||||||
0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE, 0x19, 0x1B, 0x1D, 0x1F, 0x11, 0x13, 0x15, 0x17, 0x09, 0x0B, 0x0D, 0x0F,
|
0x45, 0x47, 0x79, 0x7B, 0x7D, 0x7F, 0x71, 0x73, 0x75, 0x77, 0x69, 0x6B, 0x6D, 0x6F, 0x61, 0x63, 0x65, 0x67, 0x99, 0x9B, 0x9D, 0x9F, 0x91, 0x93, 0x95, 0x97, 0x89, 0x8B, 0x8D,
|
||||||
0x01, 0x03, 0x05, 0x07, 0x39, 0x3B, 0x3D, 0x3F, 0x31, 0x33, 0x35, 0x37, 0x29, 0x2B, 0x2D, 0x2F, 0x21, 0x23, 0x25, 0x27,
|
0x8F, 0x81, 0x83, 0x85, 0x87, 0xB9, 0xBB, 0xBD, 0xBF, 0xB1, 0xB3, 0xB5, 0xB7, 0xA9, 0xAB, 0xAD, 0xAF, 0xA1, 0xA3, 0xA5, 0xA7, 0xD9, 0xDB, 0xDD, 0xDF, 0xD1, 0xD3, 0xD5, 0xD7,
|
||||||
0x59, 0x5B, 0x5D, 0x5F, 0x51, 0x53, 0x55, 0x57, 0x49, 0x4B, 0x4D, 0x4F, 0x41, 0x43, 0x45, 0x47, 0x79, 0x7B, 0x7D, 0x7F,
|
0xC9, 0xCB, 0xCD, 0xCF, 0xC1, 0xC3, 0xC5, 0xC7, 0xF9, 0xFB, 0xFD, 0xFF, 0xF1, 0xF3, 0xF5, 0xF7, 0xE9, 0xEB, 0xED, 0xEF, 0xE1, 0xE3, 0xE5, 0xE7};
|
||||||
0x71, 0x73, 0x75, 0x77, 0x69, 0x6B, 0x6D, 0x6F, 0x61, 0x63, 0x65, 0x67, 0x99, 0x9B, 0x9D, 0x9F, 0x91, 0x93, 0x95, 0x97,
|
|
||||||
0x89, 0x8B, 0x8D, 0x8F, 0x81, 0x83, 0x85, 0x87, 0xB9, 0xBB, 0xBD, 0xBF, 0xB1, 0xB3, 0xB5, 0xB7, 0xA9, 0xAB, 0xAD, 0xAF,
|
|
||||||
0xA1, 0xA3, 0xA5, 0xA7, 0xD9, 0xDB, 0xDD, 0xDF, 0xD1, 0xD3, 0xD5, 0xD7, 0xC9, 0xCB, 0xCD, 0xCF, 0xC1, 0xC3, 0xC5, 0xC7,
|
|
||||||
0xF9, 0xFB, 0xFD, 0xFF, 0xF1, 0xF3, 0xF5, 0xF7, 0xE9, 0xEB, 0xED, 0xEF, 0xE1, 0xE3, 0xE5, 0xE7};
|
|
||||||
|
|
||||||
uint32_t EMSbus::last_bus_activity_ = 0; // timestamp of last time a valid Rx came in
|
uint32_t EMSbus::last_bus_activity_ = 0; // timestamp of last time a valid Rx came in
|
||||||
bool EMSbus::bus_connected_ = false; // start assuming the bus hasn't been connected
|
bool EMSbus::bus_connected_ = false; // start assuming the bus hasn't been connected
|
||||||
@@ -59,13 +55,7 @@ uint8_t EMSbus::calculate_crc(const uint8_t * data, const uint8_t length) {
|
|||||||
|
|
||||||
// creates a telegram object
|
// creates a telegram object
|
||||||
// stores header in separate member objects and the rest in the message_data block
|
// stores header in separate member objects and the rest in the message_data block
|
||||||
Telegram::Telegram(const uint8_t operation,
|
Telegram::Telegram(const uint8_t operation, const uint8_t src, const uint8_t dest, const uint16_t type_id, const uint8_t offset, const uint8_t * data, const uint8_t message_length)
|
||||||
const uint8_t src,
|
|
||||||
const uint8_t dest,
|
|
||||||
const uint16_t type_id,
|
|
||||||
const uint8_t offset,
|
|
||||||
const uint8_t * data,
|
|
||||||
const uint8_t message_length)
|
|
||||||
: operation(operation)
|
: operation(operation)
|
||||||
, src(src)
|
, src(src)
|
||||||
, dest(dest)
|
, dest(dest)
|
||||||
@@ -202,8 +192,7 @@ void RxService::add(uint8_t * data, uint8_t length) {
|
|||||||
// if we're watching and "raw" print out actual telegram as bytes to the console
|
// if we're watching and "raw" print out actual telegram as bytes to the console
|
||||||
if (EMSESP::watch() == EMSESP::Watch::WATCH_RAW) {
|
if (EMSESP::watch() == EMSESP::Watch::WATCH_RAW) {
|
||||||
uint16_t trace_watch_id = EMSESP::watch_id();
|
uint16_t trace_watch_id = EMSESP::watch_id();
|
||||||
if ((trace_watch_id == WATCH_ID_NONE) || (type_id == trace_watch_id)
|
if ((trace_watch_id == WATCH_ID_NONE) || (type_id == trace_watch_id) || ((trace_watch_id < 0x80) && ((src == trace_watch_id) || (dest == trace_watch_id)))) {
|
||||||
|| ((trace_watch_id < 0x80) && ((src == trace_watch_id) || (dest == trace_watch_id)))) {
|
|
||||||
LOG_NOTICE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
|
LOG_NOTICE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
|
||||||
} else if (EMSESP::trace_raw()) {
|
} else if (EMSESP::trace_raw()) {
|
||||||
LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
|
LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
|
||||||
@@ -234,13 +223,6 @@ void RxService::add(uint8_t * data, uint8_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue
|
rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue
|
||||||
|
|
||||||
/*
|
|
||||||
QueuedRxTelegram qrxt;
|
|
||||||
qrxt.telegram_ = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length);
|
|
||||||
qrxt.id_ = rx_telegram_id_++;
|
|
||||||
rx_telegrams_.push(qrxt);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// start and initialize Tx
|
// start and initialize Tx
|
||||||
@@ -285,15 +267,11 @@ void TxService::send() {
|
|||||||
}
|
}
|
||||||
delayed_send_ = 0;
|
delayed_send_ = 0;
|
||||||
|
|
||||||
// auto telegram = tx_telegrams_.pop(); // get the Telegram, also removes from queue
|
|
||||||
|
|
||||||
// if we're in read-only mode (tx_mode 0) forget the Tx call
|
// if we're in read-only mode (tx_mode 0) forget the Tx call
|
||||||
if (tx_mode() != 0) {
|
if (tx_mode() != 0) {
|
||||||
// send_telegram(telegram);
|
|
||||||
send_telegram(tx_telegrams_.front());
|
send_telegram(tx_telegrams_.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto telegram = tx_telegrams_.pop();
|
|
||||||
tx_telegrams_.pop_front(); // remove the telegram from the queue
|
tx_telegrams_.pop_front(); // remove the telegram from the queue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,10 +349,7 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
|
|||||||
|
|
||||||
length++; // add one since we want to now include the CRC
|
length++; // add one since we want to now include the CRC
|
||||||
|
|
||||||
LOG_DEBUG(F("Sending %s Tx [#%d], telegram: %s"),
|
LOG_DEBUG(F("Sending %s Tx [#%d], telegram: %s"), (telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"), tx_telegram.id_, Helpers::data_to_hex(telegram_raw, length).c_str());
|
||||||
(telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"),
|
|
||||||
tx_telegram.id_,
|
|
||||||
Helpers::data_to_hex(telegram_raw, length).c_str());
|
|
||||||
|
|
||||||
set_post_send_query(tx_telegram.validateid_);
|
set_post_send_query(tx_telegram.validateid_);
|
||||||
// send the telegram to the UART Tx
|
// send the telegram to the UART Tx
|
||||||
@@ -414,14 +389,7 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void TxService::add(const uint8_t operation,
|
void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validateid, const bool front) {
|
||||||
const uint8_t dest,
|
|
||||||
const uint16_t type_id,
|
|
||||||
const uint8_t offset,
|
|
||||||
uint8_t * message_data,
|
|
||||||
const uint8_t message_length,
|
|
||||||
const uint16_t validateid,
|
|
||||||
const bool front) {
|
|
||||||
auto telegram = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
|
auto telegram = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
|
||||||
|
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_DEBUG
|
||||||
@@ -490,7 +458,7 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
|
|||||||
if (dest & 0x80) {
|
if (dest & 0x80) {
|
||||||
operation = Telegram::Operation::TX_READ;
|
operation = Telegram::Operation::TX_READ;
|
||||||
} else {
|
} else {
|
||||||
operation = Telegram::Operation::TX_WRITE;
|
operation = Telegram::Operation::TX_WRITE;
|
||||||
validate_id = type_id;
|
validate_id = type_id;
|
||||||
}
|
}
|
||||||
EMSESP::set_read_id(type_id);
|
EMSESP::set_read_id(type_id);
|
||||||
@@ -507,13 +475,6 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
|
|||||||
LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length);
|
LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
QueuedTxTelegram qtxt;
|
|
||||||
qtxt.id_ = tx_telegram_id_++;
|
|
||||||
qtxt.retry_ = false;
|
|
||||||
qtxt.telegram_ = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (front) {
|
if (front) {
|
||||||
// tx_telegrams_.push_front(qtxt); // add to front of queue
|
// tx_telegrams_.push_front(qtxt); // add to front of queue
|
||||||
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false, validate_id); // add to front of queue
|
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false, validate_id); // add to front of queue
|
||||||
@@ -580,9 +541,7 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
|
|||||||
reset_retry_count(); // give up
|
reset_retry_count(); // give up
|
||||||
increment_telegram_fail_count(); // another Tx fail
|
increment_telegram_fail_count(); // another Tx fail
|
||||||
|
|
||||||
LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request."),
|
LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request."), (operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"), MAXIMUM_TX_RETRIES);
|
||||||
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
|
|
||||||
MAXIMUM_TX_RETRIES);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,14 +559,6 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram_last_), true, get_post_send_query());
|
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram_last_), true, get_post_send_query());
|
||||||
|
|
||||||
/*
|
|
||||||
QueuedTxTelegram qtxt;
|
|
||||||
qtxt.id_ = tx_telegram_id_++;
|
|
||||||
qtxt.retry_ = true; // this time it is a retry
|
|
||||||
qtxt.telegram_ = telegram_last_;
|
|
||||||
tx_telegrams_.push_front(qtxt); // add to front of queue
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t TxService::read_next_tx() {
|
uint16_t TxService::read_next_tx() {
|
||||||
@@ -635,7 +586,7 @@ uint16_t TxService::post_send_query() {
|
|||||||
uint8_t dest = (this->telegram_last_->dest & 0x7F);
|
uint8_t dest = (this->telegram_last_->dest & 0x7F);
|
||||||
// when set a value with large offset before and validate on same type, we have to add offset 0, 26, 52, ...
|
// when set a value with large offset before and validate on same type, we have to add offset 0, 26, 52, ...
|
||||||
uint8_t offset = (this->telegram_last_->type_id == post_typeid) ? ((this->telegram_last_->offset / 26) * 26) : 0;
|
uint8_t offset = (this->telegram_last_->type_id == post_typeid) ? ((this->telegram_last_->offset / 26) * 26) : 0;
|
||||||
uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes
|
uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes
|
||||||
this->add(Telegram::Operation::TX_READ, dest, post_typeid, offset, message_data, 1, 0, true); // add to top/front of queue
|
this->add(Telegram::Operation::TX_READ, dest, post_typeid, offset, message_data, 1, 0, true); // add to top/front of queue
|
||||||
// read_request(telegram_last_post_send_query_, dest, 0); // no offset
|
// read_request(telegram_last_post_send_query_, dest, 0); // no offset
|
||||||
LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), post_typeid, dest);
|
LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), post_typeid, dest);
|
||||||
|
|||||||
@@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
#include <uuid/log.h>
|
#include <uuid/log.h>
|
||||||
|
|
||||||
// #include "containers.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
|
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
|
||||||
@@ -219,7 +218,11 @@ class RxService : public EMSbus {
|
|||||||
if (telegram_error_count_ == 0) {
|
if (telegram_error_count_ == 0) {
|
||||||
return 100; // all good, 100%
|
return 100; // all good, 100%
|
||||||
}
|
}
|
||||||
|
if (telegram_error_count_ >= telegram_count_) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
uint8_t q = ((float)telegram_error_count_ / telegram_count_ * 100);
|
uint8_t q = ((float)telegram_error_count_ / telegram_count_ * 100);
|
||||||
|
|
||||||
return (q <= EMS_BUS_QUALITY_RX_THRESHOLD ? 100 : 100 - q);
|
return (q <= EMS_BUS_QUALITY_RX_THRESHOLD ? 100 : 100 - q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,17 +242,6 @@ class RxService : public EMSbus {
|
|||||||
return rx_telegrams_;
|
return rx_telegrams_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct QueuedRxTelegram {
|
|
||||||
uint16_t id_;
|
|
||||||
std::shared_ptr<const Telegram> telegram_;
|
|
||||||
};
|
|
||||||
|
|
||||||
const emsesp::queue<QueuedRxTelegram> queue() const {
|
|
||||||
return rx_telegrams_;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t EMS_BUS_QUALITY_RX_THRESHOLD = 5; // % threshold before reporting quality issues
|
static constexpr uint8_t EMS_BUS_QUALITY_RX_THRESHOLD = 5; // % threshold before reporting quality issues
|
||||||
|
|
||||||
@@ -258,7 +250,6 @@ class RxService : public EMSbus {
|
|||||||
uint32_t telegram_error_count_ = 0; // # Rx CRC errors
|
uint32_t telegram_error_count_ = 0; // # Rx CRC errors
|
||||||
std::shared_ptr<const Telegram> rx_telegram; // the incoming Rx telegram
|
std::shared_ptr<const Telegram> rx_telegram; // the incoming Rx telegram
|
||||||
std::deque<QueuedRxTelegram> rx_telegrams_; // the Rx Queue
|
std::deque<QueuedRxTelegram> rx_telegrams_; // the Rx Queue
|
||||||
// emsesp::queue<QueuedRxTelegram> rx_telegrams_ = emsesp::queue<QueuedRxTelegram>(MAX_RX_TELEGRAMS); // the Rx Queue
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TxService : public EMSbus {
|
class TxService : public EMSbus {
|
||||||
@@ -271,7 +262,7 @@ class TxService : public EMSbus {
|
|||||||
|
|
||||||
void start();
|
void start();
|
||||||
void send();
|
void send();
|
||||||
void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validateid, const bool front = false);
|
void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validateid, const bool front = false);
|
||||||
void add(const uint8_t operation, const uint8_t * data, const uint8_t length, const uint16_t validateid, const bool front = false);
|
void add(const uint8_t operation, const uint8_t * data, const uint8_t length, const uint16_t validateid, const bool front = false);
|
||||||
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0);
|
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0);
|
||||||
void send_raw(const char * telegram_data);
|
void send_raw(const char * telegram_data);
|
||||||
@@ -321,6 +312,9 @@ class TxService : public EMSbus {
|
|||||||
if (telegram_fail_count_ == 0) {
|
if (telegram_fail_count_ == 0) {
|
||||||
return 100; // all good, 100%
|
return 100; // all good, 100%
|
||||||
}
|
}
|
||||||
|
if (telegram_fail_count_ >= telegram_read_count_) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
return (100 - (uint8_t)(((float)telegram_fail_count_ / telegram_read_count_ * 100)));
|
return (100 - (uint8_t)(((float)telegram_fail_count_ / telegram_read_count_ * 100)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,18 +353,6 @@ class TxService : public EMSbus {
|
|||||||
return tx_telegrams_;
|
return tx_telegrams_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct QueuedTxTelegram {
|
|
||||||
uint16_t id_;
|
|
||||||
std::shared_ptr<const Telegram> telegram_;
|
|
||||||
bool retry_; // true if its a retry
|
|
||||||
};
|
|
||||||
|
|
||||||
const emsesp::queue<QueuedTxTelegram> queue() const {
|
|
||||||
return tx_telegrams_;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
static constexpr uint8_t MAXIMUM_TX_RETRIES = 0; // when compiled with EMSESP_DEBUG don't retry
|
static constexpr uint8_t MAXIMUM_TX_RETRIES = 0; // when compiled with EMSESP_DEBUG don't retry
|
||||||
#else
|
#else
|
||||||
@@ -380,7 +362,6 @@ class TxService : public EMSbus {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::deque<QueuedTxTelegram> tx_telegrams_; // the Tx queue
|
std::deque<QueuedTxTelegram> tx_telegrams_; // the Tx queue
|
||||||
// emsesp::queue<QueuedTxTelegram> tx_telegrams_ = emsesp::queue<QueuedTxTelegram>(MAX_TX_TELEGRAMS); // the Tx Queue
|
|
||||||
|
|
||||||
uint32_t telegram_read_count_ = 0; // # Tx successful reads
|
uint32_t telegram_read_count_ = 0; // # Tx successful reads
|
||||||
uint32_t telegram_write_count_ = 0; // # Tx successful writes
|
uint32_t telegram_write_count_ = 0; // # Tx successful writes
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
// create some fake test data
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
// no shell
|
// no shell
|
||||||
@@ -366,14 +364,39 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command == "board_profile") {
|
||||||
|
shell.printfln(F("Testing board profile..."));
|
||||||
|
|
||||||
|
shell.invoke_command("system");
|
||||||
|
shell.invoke_command("set board_profile wemos");
|
||||||
|
shell.invoke_command("exit");
|
||||||
|
shell.invoke_command("call system settings");
|
||||||
|
}
|
||||||
|
|
||||||
if (command == "boiler") {
|
if (command == "boiler") {
|
||||||
shell.printfln(F("Testing boiler..."));
|
shell.printfln(F("Testing boiler..."));
|
||||||
|
Mqtt::ha_enabled(false);
|
||||||
|
Mqtt::nested_format(true);
|
||||||
|
|
||||||
run_test("boiler");
|
run_test("boiler");
|
||||||
shell.invoke_command("show devices");
|
shell.invoke_command("show devices");
|
||||||
shell.invoke_command("show");
|
shell.invoke_command("show");
|
||||||
// shell.invoke_command("call boiler info");
|
shell.invoke_command("call boiler info");
|
||||||
// shell.invoke_command("call system publish");
|
shell.invoke_command("call system publish");
|
||||||
// shell.invoke_command("show mqtt");
|
|
||||||
|
// test all permutations
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "1");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "0");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "on");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler/heatingtemp", "24");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "test"); // should fail
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler", "{\"cmd\":\"flowtemp\",\"id\":0,\"data\":22}");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler", "{\"cmd\":\"wwonetime\",\"id\":0,\"data\":1}");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler", "{\"cmd\":\"wwonetime\",\"id\":0,\"data\":\"off\"}");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler", "{\"cmd\":\"wwonetime\",\"hc\":1,\"data\":\"on\"}");
|
||||||
|
EMSESP::mqtt_.incoming("ems-esp/boiler", "{\"cmd\":\"wwonetime\",\"data\":\"on\",\"hc\":1}");
|
||||||
|
|
||||||
|
shell.invoke_command("show mqtt");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "fr120") {
|
if (command == "fr120") {
|
||||||
|
|||||||
@@ -32,8 +32,9 @@ namespace emsesp {
|
|||||||
// #define EMSESP_TEST_DEFAULT "general"
|
// #define EMSESP_TEST_DEFAULT "general"
|
||||||
// #define EMSESP_TEST_DEFAULT "boiler"
|
// #define EMSESP_TEST_DEFAULT "boiler"
|
||||||
// #define EMSESP_TEST_DEFAULT "mqtt2"
|
// #define EMSESP_TEST_DEFAULT "mqtt2"
|
||||||
#define EMSESP_TEST_DEFAULT "mqtt_nested"
|
// #define EMSESP_TEST_DEFAULT "mqtt_nested"
|
||||||
// #define EMSESP_TEST_DEFAULT "ha"
|
// #define EMSESP_TEST_DEFAULT "ha"
|
||||||
|
#define EMSESP_TEST_DEFAULT "board_profile"
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -67,8 +67,10 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
|
|||||||
drop_next_rx_ = true; // we have a overflow
|
drop_next_rx_ = true; // we have a overflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rxbuf[length - 1]) { // check if last byte is break
|
if (length > 0 && length < EMS_MAXBUFFERSIZE) {
|
||||||
length++;
|
if (rxbuf[length - 1]) { // check if last byte is break
|
||||||
|
length++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((!drop_next_rx_) && ((length == 2) || (length > 4))) {
|
if ((!drop_next_rx_) && ((length == 2) || (length > 4))) {
|
||||||
int baseType = 0;
|
int baseType = 0;
|
||||||
|
|||||||
@@ -46,10 +46,10 @@
|
|||||||
#define EMS_TXMODE_HW 4
|
#define EMS_TXMODE_HW 4
|
||||||
|
|
||||||
// LEGACY
|
// LEGACY
|
||||||
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
|
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
|
||||||
|
|
||||||
// EMS 1.0
|
// EMS 1.0
|
||||||
#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13
|
#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13
|
||||||
#define EMSUART_TX_TIMEOUT (20 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT)
|
#define EMSUART_TX_TIMEOUT (20 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT)
|
||||||
#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10)
|
#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10)
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define EMSESP_APP_VERSION "3.0.0"
|
#define EMSESP_APP_VERSION "3.0.1"
|
||||||
#define EMSESP_PLATFORM "ESP32"
|
#define EMSESP_PLATFORM "ESP32"
|
||||||
|
|||||||
Reference in New Issue
Block a user