mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
Merge remote-tracking branch 'origin/dev'
This commit is contained in:
75
CHANGELOG.md
75
CHANGELOG.md
@@ -5,19 +5,42 @@ 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/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# Changelog
|
||||
# [3.4.2]
|
||||
|
||||
## [3.4.1] May 29 2022
|
||||
## Added
|
||||
|
||||
### Fixed
|
||||
- RC310 additions [#520](https://github.com/emsesp/EMS-ESP32/pull/520)
|
||||
- damping
|
||||
- wwprio for RC310 heating circuits
|
||||
- switchonoptimization for RC310 heating circuits
|
||||
- enum_controlmode for RC310 (new enum list)
|
||||
- nofrostmode, reducemode, reducetemp & noreducetemp for RC310
|
||||
- emergencyops and emergencytemp, wwmaxtemp, wwflowtempoffset and wwcomfort1 for RC310
|
||||
- HM200 hybrid module [#500](https://github.com/emsesp/EMS-ESP32/issues/500)
|
||||
- AM200 alternative heatsource module [#573](https://github.com/emsesp/EMS-ESP32/issues/573)
|
||||
- EM10 error module as gateway [#575](https://github.com/emsesp/EMS-ESP32/issues/575)
|
||||
|
||||
## Fixed
|
||||
|
||||
- fix Table resizing in WebUI [#519](https://github.com/emsesp/EMS-ESP32/issues/519)
|
||||
- allow larger customization files [#570](https://github.com/emsesp/EMS-ESP32/issues/570)
|
||||
- losing entitiy wwcomfort [#581](https://github.com/emsesp/EMS-ESP32/issues/581)
|
||||
|
||||
## Changed
|
||||
|
||||
- Shorten "friendly names" in Home Assistant [#555](https://github.com/emsesp/EMS-ESP32/issues/555)
|
||||
|
||||
- platformio 2.3.0 (IDF 4, Arduino 2)
|
||||
- remove master-thermostat, support multiple thermostats
|
||||
- merge up- and download in webui [#577](https://github.com/emsesp/EMS-ESP32/issues/577)
|
||||
|
||||
# [3.4.1] May 29 2022
|
||||
|
||||
## Fixed
|
||||
|
||||
- Fix memory leak in api [#524](https://github.com/emsesp/EMS-ESP32/issues/524)
|
||||
|
||||
### Changed
|
||||
|
||||
- Controller data in web-ui only for IVT [#522](https://github.com/emsesp/EMS-ESP32/issues/522)
|
||||
- Rename hidden `climate` to a more explaining name [#523](https://github.com/emsesp/EMS-ESP32/issues/523)
|
||||
- Minor changes to the Customizations web page [#527](https://github.com/emsesp/EMS-ESP32/pull/527)
|
||||
## Changed
|
||||
|
||||
# [3.4.0] May 23 2022
|
||||
|
||||
@@ -284,51 +307,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## 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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -141,7 +141,7 @@ run: $(OUTPUT)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(RM) -r $(BUILD) $(OUTPUT)
|
||||
@$(RM) -rf $(BUILD) $(OUTPUT)
|
||||
|
||||
help:
|
||||
@echo available targets: all run clean
|
||||
|
||||
@@ -3,4 +3,3 @@
|
||||
# Firmware Installation
|
||||
|
||||
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.
|
||||
|
||||
|
||||
@@ -5,4 +5,3 @@ This is a snapshot of the current "beta" development code and firmware binaries
|
||||
# Firmware Installation
|
||||
|
||||
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.
|
||||
|
||||
|
||||
8883
interface/package-lock.json
generated
8883
interface/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,33 +4,33 @@
|
||||
"private": true,
|
||||
"proxy": "http://localhost:3080",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
"@msgpack/msgpack": "^2.7.2",
|
||||
"@mui/icons-material": "^5.8.0",
|
||||
"@mui/material": "^5.8.1",
|
||||
"@table-library/react-table-library": "^3.1.4",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/node": "^17.0.36",
|
||||
"@types/react": "^18.0.9",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"@emotion/react": "^11.10.4",
|
||||
"@emotion/styled": "^11.10.4",
|
||||
"@msgpack/msgpack": "^2.8.0",
|
||||
"@mui/icons-material": "^5.10.3",
|
||||
"@mui/material": "^5.10.5",
|
||||
"@table-library/react-table-library": "4.0.18",
|
||||
"@types/lodash": "^4.14.185",
|
||||
"@types/node": "^18.7.18",
|
||||
"@types/react": "^18.0.20",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"async-validator": "^4.1.1",
|
||||
"async-validator": "^4.2.5",
|
||||
"axios": "^0.27.2",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^2.0.5",
|
||||
"parse-ms": "^3.0.0",
|
||||
"react": "^18.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-app-rewired": "^2.2.1",
|
||||
"react-dom": "^18.1.0",
|
||||
"react-dropzone": "^14.2.1",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-dropzone": "^14.2.2",
|
||||
"react-icons": "^4.4.0",
|
||||
"react-router-dom": "^6.4.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"sockette": "^2.0.6",
|
||||
"typescript": "^4.7.2"
|
||||
"typescript": "^4.8.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-app-rewired start",
|
||||
@@ -97,7 +97,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.16",
|
||||
"nodemon": "^2.0.20",
|
||||
"npm-run-all": "^4.1.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ const MqttSettingsForm: FC = () => {
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors}
|
||||
name="base"
|
||||
label="Bsse"
|
||||
label="Base"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.base}
|
||||
|
||||
@@ -35,43 +35,44 @@ const ManageUsersForm: FC = () => {
|
||||
const authenticatedContext = useContext(AuthenticatedContext);
|
||||
|
||||
const table_theme = useTheme({
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 90px 120px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
padding-left: 8px;
|
||||
`,
|
||||
HeaderRow: `
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
color: #90CAF9;
|
||||
.th {
|
||||
padding: 8px;
|
||||
height: 42px;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #565656;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
&:nth-of-type(odd) {
|
||||
background-color: #303030;
|
||||
}
|
||||
&:nth-of-type(even) {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
.td {
|
||||
padding: 8px;
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
&:not(:first-of-type) {
|
||||
margin-top: -1px;
|
||||
|
||||
&:nth-of-type(odd) .td {
|
||||
background-color: #303030;
|
||||
}
|
||||
&:hover {
|
||||
color: white;
|
||||
&:nth-of-type(even) .td {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
&:nth-of-type(2) {
|
||||
text-align: center;
|
||||
}
|
||||
&:last-of-type {
|
||||
text-align: right;
|
||||
}
|
||||
`
|
||||
});
|
||||
|
||||
@@ -130,22 +131,22 @@ const ManageUsersForm: FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Table data={{ nodes: user_table }} theme={table_theme}>
|
||||
<Table data={{ nodes: user_table }} theme={table_theme} layout={{ custom: true }}>
|
||||
{(tableList: any) => (
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell>USERNAME</HeaderCell>
|
||||
<HeaderCell>IS ADMIN</HeaderCell>
|
||||
<HeaderCell />
|
||||
<HeaderCell resize>USERNAME</HeaderCell>
|
||||
<HeaderCell stiff>IS ADMIN</HeaderCell>
|
||||
<HeaderCell stiff />
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((u: any) => (
|
||||
<Row key={u.id} item={u}>
|
||||
<Cell>{u.username}</Cell>
|
||||
<Cell>{u.admin ? <CheckIcon /> : <CloseIcon />}</Cell>
|
||||
<Cell>
|
||||
<Cell stiff>{u.admin ? <CheckIcon /> : <CloseIcon />}</Cell>
|
||||
<Cell stiff>
|
||||
<IconButton
|
||||
size="small"
|
||||
disabled={!authenticatedContext.me.admin}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { FC } from 'react';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
import { Typography, Button, Box } from '@mui/material';
|
||||
|
||||
import { FileUploadConfig } from '../../api/endpoints';
|
||||
import { MessageBox, SingleUpload, useFileUpload } from '../../components';
|
||||
import { SingleUpload, useFileUpload } from '../../components';
|
||||
|
||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||
|
||||
import { useSnackbar } from 'notistack';
|
||||
|
||||
import { extractErrorMessage } from '../../utils';
|
||||
|
||||
import * as EMSESP from '../../project/api';
|
||||
|
||||
interface UploadFileProps {
|
||||
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
||||
@@ -11,16 +21,93 @@ interface UploadFileProps {
|
||||
const GeneralFileUpload: FC<UploadFileProps> = ({ uploadGeneralFile }) => {
|
||||
const [uploadFile, cancelUpload, uploading, uploadProgress] = useFileUpload({ upload: uploadGeneralFile });
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const saveFile = (json: any, endpoint: string) => {
|
||||
const a = document.createElement('a');
|
||||
const filename = 'emsesp_' + endpoint + '.json';
|
||||
a.href = URL.createObjectURL(
|
||||
new Blob([JSON.stringify(json, null, 2)], {
|
||||
type: 'text/plain'
|
||||
})
|
||||
);
|
||||
a.setAttribute('download', filename);
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
enqueueSnackbar('File downloaded', { variant: 'info' });
|
||||
};
|
||||
|
||||
const downloadSettings = async () => {
|
||||
try {
|
||||
const response = await EMSESP.getSettings();
|
||||
if (response.status !== 200) {
|
||||
enqueueSnackbar('Unable to get settings', { variant: 'error' });
|
||||
} else {
|
||||
saveFile(response.data, 'settings');
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
const downloadCustomizations = async () => {
|
||||
try {
|
||||
const response = await EMSESP.getCustomizations();
|
||||
if (response.status !== 200) {
|
||||
enqueueSnackbar('Unable to get customizations', { variant: 'error' });
|
||||
} else {
|
||||
saveFile(response.data, 'customizations');
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||
Upload
|
||||
</Typography>
|
||||
{!uploading && (
|
||||
<MessageBox
|
||||
message="Upload a new firmware (.bin) file or an exported settings or customizations (.json) file below. EMS-ESP will restart afterwards to apply the new changes."
|
||||
level="warning"
|
||||
my={2}
|
||||
/>
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body2">
|
||||
Upload a new firmware (.bin) file, settings or customizations (.json) file below.
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<SingleUpload onDrop={uploadFile} onCancel={cancelUpload} uploading={uploading} progress={uploadProgress} />
|
||||
|
||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||
Download
|
||||
</Typography>
|
||||
{!uploading && (
|
||||
<>
|
||||
<Box color="warning.main">
|
||||
<Typography mb={1} variant="body2">
|
||||
Download the application settings. Be careful when sharing your settings as this file contains passwords
|
||||
and other sensitive system information.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => downloadSettings()}>
|
||||
settings
|
||||
</Button>
|
||||
|
||||
<Box color="warning.main">
|
||||
<Typography mt={2} mb={1} variant="body2">
|
||||
Download the entity customizations.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => downloadCustomizations()}
|
||||
>
|
||||
customizations
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ const System: FC = () => {
|
||||
<Tab value="log" label="System Log" />
|
||||
|
||||
{features.ota && <Tab value="ota" label="OTA Settings" disabled={!me.admin} />}
|
||||
{features.upload_firmware && <Tab value="upload" label="Upload" disabled={!me.admin} />}
|
||||
{features.upload_firmware && <Tab value="upload" label="Upload/Download" disabled={!me.admin} />}
|
||||
</RouterTabs>
|
||||
<Routes>
|
||||
<Route path="status" element={<SystemStatusForm />} />
|
||||
|
||||
@@ -17,7 +17,7 @@ const UploadFileForm: FC = () => {
|
||||
});
|
||||
|
||||
return (
|
||||
<SectionContent title="Upload File" titleGutter>
|
||||
<SectionContent title="Upload/Download" titleGutter>
|
||||
{restarting ? <RestartMonitor /> : <GeneralFileUpload uploadGeneralFile={uploadFile.current} />}
|
||||
</SectionContent>
|
||||
);
|
||||
|
||||
@@ -79,7 +79,7 @@ const DashboardData: FC = () => {
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const [coreData, setCoreData] = useState<CoreData>({ devices: [], active_sensors: 0, analog_enabled: false });
|
||||
const [coreData, setCoreData] = useState<CoreData>({ connected: true, devices: [], active_sensors: 0, analog_enabled: false });
|
||||
const [deviceData, setDeviceData] = useState<DeviceData>({ label: '', data: [] });
|
||||
const [sensorData, setSensorData] = useState<SensorData>({ sensors: [], analogs: [] });
|
||||
const [deviceValue, setDeviceValue] = useState<DeviceValue>();
|
||||
@@ -88,183 +88,119 @@ const DashboardData: FC = () => {
|
||||
const [deviceDialog, setDeviceDialog] = useState<number>(-1);
|
||||
const [onlyFav, setOnlyFav] = useState(false);
|
||||
|
||||
const device_theme = useTheme({
|
||||
const common_theme = useTheme({
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
height: 46px;
|
||||
&:focus {
|
||||
z-index: 2;
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
`,
|
||||
HeaderRow: `
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
color: #90CAF9;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-weight: 500;
|
||||
|
||||
.th {
|
||||
border-bottom: 1px solid #565656;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
background-color: #1e1e1e;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
.td {
|
||||
padding: 8px;
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
&:not(:first-of-type) {
|
||||
margin-top: -1px;
|
||||
}
|
||||
&:hover {
|
||||
z-index: 2;
|
||||
color: white;
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
},
|
||||
&.tr.tr-body.row-select.row-select-single-selected, &.tr.tr-body.row-select.row-select-selected {
|
||||
|
||||
&.tr.tr-body.row-select.row-select-single-selected {
|
||||
background-color: #3d4752;
|
||||
color: white;
|
||||
font-weight: normal;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:hover .td {
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
&:not(.stiff) > div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
&:nth-of-type(1) {
|
||||
padding-left: 8px;
|
||||
min-width: 42px;
|
||||
width: 42px;
|
||||
div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
min-width: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
flex: 1;
|
||||
}
|
||||
&:nth-of-type(4) {
|
||||
text-align: center;
|
||||
max-width: 100px;
|
||||
}
|
||||
Cell: `
|
||||
&:last-of-type {
|
||||
padding-left: 0px;
|
||||
text-align: center;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
}
|
||||
text-align: right;
|
||||
},
|
||||
`
|
||||
});
|
||||
|
||||
const data_theme = useTheme({
|
||||
const device_theme = useTheme([
|
||||
common_theme,
|
||||
{
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: 40px 100px repeat(1, minmax(0, 1fr)) 80px 40px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
height: 32px;
|
||||
`,
|
||||
HeaderRow: `
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
color: #90CAF9;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-weight: 500;
|
||||
`,
|
||||
Row: `
|
||||
&:nth-of-type(odd) {
|
||||
background-color: #303030;
|
||||
}
|
||||
&:nth-of-type(even) {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
&:not(:first-of-type) {
|
||||
margin-top: -1px;
|
||||
}
|
||||
&:hover {
|
||||
z-index: 2;
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
color: white;
|
||||
.td {
|
||||
height: 42px;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
padding-left: 16px;
|
||||
cursor: pointer;
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
&:not(.stiff) > div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
&:nth-of-type(1) {
|
||||
width: 260px;
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
}
|
||||
&:last-of-type {
|
||||
padding-left: 0px;
|
||||
text-align: left;
|
||||
},
|
||||
&:nth-of-type(4) {
|
||||
text-align: center;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
}
|
||||
`,
|
||||
HeaderCell: `
|
||||
&:not(:last-of-type) {
|
||||
padding-left: 8px;
|
||||
border-left: 1px solid #565656;
|
||||
HeaderRow: `
|
||||
.th {
|
||||
padding: 8px;
|
||||
height: 42px;
|
||||
font-weight: 500;
|
||||
`
|
||||
}
|
||||
&:first-of-type {
|
||||
border-left: 0px;
|
||||
]);
|
||||
|
||||
const data_theme = useTheme([
|
||||
common_theme,
|
||||
{
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 140px 40px;
|
||||
`,
|
||||
BaseRow: `
|
||||
.td {
|
||||
height: 32px;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
&:nth-of-type(2) {
|
||||
text-align: right;
|
||||
},
|
||||
`,
|
||||
HeaderRow: `
|
||||
.th {
|
||||
height: 32px;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
&:nth-of-type(odd) .td {
|
||||
background-color: #303030;
|
||||
}
|
||||
`
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
const temperature_theme = useTheme([data_theme]);
|
||||
|
||||
const analog_theme = useTheme([
|
||||
data_theme,
|
||||
{
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: 80px repeat(1, minmax(0, 1fr)) 120px 100px 40px;
|
||||
`,
|
||||
BaseCell: `
|
||||
&:nth-of-type(1) {
|
||||
width: 100px;
|
||||
min-width: 100px;
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
text-align: left;
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
width: 100px;
|
||||
min-width: 100px;
|
||||
}
|
||||
},
|
||||
&:nth-of-type(4) {
|
||||
text-align: right;
|
||||
flex: 1;
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -536,6 +472,7 @@ const DashboardData: FC = () => {
|
||||
label={deviceValue.id.slice(2)}
|
||||
value={deviceValue.u ? numberValue(deviceValue.v) : deviceValue.v}
|
||||
autoFocus
|
||||
multiline={deviceValue.u ? false : true}
|
||||
sx={{ width: '30ch' }}
|
||||
type={deviceValue.u ? 'number' : 'text'}
|
||||
onChange={updateValue(setDeviceValue)}
|
||||
@@ -703,29 +640,30 @@ const DashboardData: FC = () => {
|
||||
|
||||
const renderCoreData = () => (
|
||||
<IconContext.Provider value={{ color: 'lightblue', size: '24', style: { verticalAlign: 'middle' } }}>
|
||||
{coreData.devices.length === 0 && <MessageBox my={2} level="warning" message="Scanning for EMS devices..." />}
|
||||
{!coreData.connected && <MessageBox my={2} level="error" message="EMSbus disconnected, check settings and board profile" />}
|
||||
{coreData.connected && coreData.devices.length === 0 && <MessageBox my={2} level="warning" message="Scanning for EMS devices..." />}
|
||||
<Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}>
|
||||
{(tableList: any) => (
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell />
|
||||
<HeaderCell>TYPE</HeaderCell>
|
||||
<HeaderCell>DESCRIPTION</HeaderCell>
|
||||
<HeaderCell>ENTITIES</HeaderCell>
|
||||
<HeaderCell />
|
||||
<HeaderCell stiff />
|
||||
<HeaderCell stiff>TYPE</HeaderCell>
|
||||
<HeaderCell resize>DESCRIPTION</HeaderCell>
|
||||
<HeaderCell stiff>ENTITIES</HeaderCell>
|
||||
<HeaderCell stiff />
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((device: Device, index: number) => (
|
||||
<Row key={device.id} item={device}>
|
||||
<Cell>
|
||||
<Cell stiff>
|
||||
<DeviceIcon type={device.t} />
|
||||
</Cell>
|
||||
<Cell>{device.t}</Cell>
|
||||
<Cell stiff>{device.t}</Cell>
|
||||
<Cell>{device.n}</Cell>
|
||||
<Cell>{device.e}</Cell>
|
||||
<Cell>
|
||||
<Cell stiff>{device.e}</Cell>
|
||||
<Cell stiff>
|
||||
<IconButton size="small" onClick={() => setDeviceDialog(index)}>
|
||||
<InfoOutlinedIcon color="info" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
|
||||
</IconButton>
|
||||
@@ -778,7 +716,7 @@ const DashboardData: FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="primary">
|
||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
||||
{deviceData.label}
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
@@ -814,7 +752,7 @@ const DashboardData: FC = () => {
|
||||
ENTITY NAME
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell>
|
||||
<HeaderCell resize>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{ fontSize: '14px', justifyContent: 'flex-end' }}
|
||||
@@ -824,7 +762,7 @@ const DashboardData: FC = () => {
|
||||
VALUE
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell />
|
||||
<HeaderCell stiff />
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
@@ -832,7 +770,7 @@ const DashboardData: FC = () => {
|
||||
<Row key={dv.id} item={dv} onClick={() => sendCommand(dv)}>
|
||||
<Cell>{renderNameCell(dv)}</Cell>
|
||||
<Cell>{formatValue(dv.v, dv.u)}</Cell>
|
||||
<Cell>
|
||||
<Cell stiff>
|
||||
{dv.c && me.admin && !hasMask(dv.id, DeviceEntityMask.DV_READONLY) && (
|
||||
<IconButton size="small" onClick={() => sendCommand(dv)}>
|
||||
{isCmdOnly(dv) ? (
|
||||
@@ -867,7 +805,7 @@ const DashboardData: FC = () => {
|
||||
|
||||
const renderDallasData = () => (
|
||||
<>
|
||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="primary">
|
||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
||||
Temperature Sensors
|
||||
</Typography>
|
||||
<Table
|
||||
@@ -890,7 +828,7 @@ const DashboardData: FC = () => {
|
||||
NAME
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell>
|
||||
<HeaderCell stiff>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{ fontSize: '14px', justifyContent: 'flex-end' }}
|
||||
@@ -900,7 +838,7 @@ const DashboardData: FC = () => {
|
||||
TEMPERATURE
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell />
|
||||
<HeaderCell stiff />
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
@@ -926,7 +864,7 @@ const DashboardData: FC = () => {
|
||||
|
||||
const renderAnalogData = () => (
|
||||
<>
|
||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="primary">
|
||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
||||
Analog Sensors
|
||||
</Typography>
|
||||
|
||||
@@ -935,7 +873,7 @@ const DashboardData: FC = () => {
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell resize>
|
||||
<HeaderCell stiff>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{ fontSize: '14px', justifyContent: 'flex-start' }}
|
||||
@@ -955,7 +893,7 @@ const DashboardData: FC = () => {
|
||||
NAME
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell resize>
|
||||
<HeaderCell stiff>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{ fontSize: '14px', justifyContent: 'flex-start' }}
|
||||
@@ -965,18 +903,18 @@ const DashboardData: FC = () => {
|
||||
TYPE
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell>VALUE</HeaderCell>
|
||||
<HeaderCell />
|
||||
<HeaderCell stiff>VALUE</HeaderCell>
|
||||
<HeaderCell stiff />
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((a: Analog) => (
|
||||
<Row key={a.id} item={a} onClick={() => updateAnalog(a)}>
|
||||
<Cell>{a.g}</Cell>
|
||||
<Cell stiff>{a.g}</Cell>
|
||||
<Cell>{a.n}</Cell>
|
||||
<Cell>{AnalogTypeNames[a.t]} </Cell>
|
||||
<Cell>{a.t ? formatValue(a.v, a.u) : ''}</Cell>
|
||||
<Cell>
|
||||
<Cell stiff>{AnalogTypeNames[a.t]} </Cell>
|
||||
<Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell>
|
||||
<Cell stiff>
|
||||
{me.admin && (
|
||||
<IconButton onClick={() => updateAnalog(a)}>
|
||||
<EditIcon color="primary" sx={{ fontSize: 16 }} />
|
||||
|
||||
@@ -88,65 +88,40 @@ const DashboardStatus: FC = () => {
|
||||
const { me } = useContext(AuthenticatedContext);
|
||||
|
||||
const stats_theme = tableTheme({
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 90px 90px 80px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
height: 32px;
|
||||
`,
|
||||
HeaderRow: `
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
color: #90CAF9;
|
||||
|
||||
.th {
|
||||
height: 42px;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding-left: 8px;
|
||||
border-bottom: 1px solid #565656;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
&:nth-of-type(odd) {
|
||||
background-color: #303030;
|
||||
}
|
||||
&:nth-of-type(even) {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
.td {
|
||||
padding: 8px;
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
&:not(:first-of-type) {
|
||||
margin-top: -1px;
|
||||
|
||||
&:nth-of-type(odd) .td {
|
||||
background-color: #303030;
|
||||
}
|
||||
&:hover {
|
||||
color: white;
|
||||
&:nth-of-type(even) .td {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
&:not(.stiff) > div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
&:nth-of-type(1) {
|
||||
padding-left: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
width: 70px;
|
||||
text-align: right;
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
}
|
||||
&:last-of-type {
|
||||
width: 75px;
|
||||
text-align: right;
|
||||
padding-right: 8px;
|
||||
&:not(:first-of-type) {
|
||||
text-align: center;
|
||||
}
|
||||
`
|
||||
});
|
||||
@@ -224,19 +199,19 @@ const DashboardStatus: FC = () => {
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell></HeaderCell>
|
||||
<HeaderCell>SUCCESS</HeaderCell>
|
||||
<HeaderCell>FAIL</HeaderCell>
|
||||
<HeaderCell>QUALITY</HeaderCell>
|
||||
<HeaderCell resize></HeaderCell>
|
||||
<HeaderCell stiff>SUCCESS</HeaderCell>
|
||||
<HeaderCell stiff>FAIL</HeaderCell>
|
||||
<HeaderCell stiff>QUALITY</HeaderCell>
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((stat: Stat) => (
|
||||
<Row key={stat.id} item={stat}>
|
||||
<Cell>{stat.id}</Cell>
|
||||
<Cell>{Intl.NumberFormat().format(stat.s)}</Cell>
|
||||
<Cell>{Intl.NumberFormat().format(stat.f)}</Cell>
|
||||
<Cell>{showQuality(stat)}</Cell>
|
||||
<Cell stiff>{Intl.NumberFormat().format(stat.s)}</Cell>
|
||||
<Cell stiff>{Intl.NumberFormat().format(stat.f)}</Cell>
|
||||
<Cell stiff>{showQuality(stat)}</Cell>
|
||||
</Row>
|
||||
))}
|
||||
</Body>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { FC, useContext } from 'react';
|
||||
import { FC } from 'react';
|
||||
|
||||
import { Typography, Button, Box, List, ListItem, ListItemText, Link, ListItemAvatar } from '@mui/material';
|
||||
|
||||
import { SectionContent, ButtonRow, MessageBox } from '../components';
|
||||
|
||||
import { AuthenticatedContext } from '../contexts/authentication';
|
||||
import { SectionContent } from '../components';
|
||||
|
||||
import { useSnackbar } from 'notistack';
|
||||
|
||||
@@ -13,7 +11,6 @@ import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
|
||||
import GitHubIcon from '@mui/icons-material/GitHub';
|
||||
import StarIcon from '@mui/icons-material/Star';
|
||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||
import TuneIcon from '@mui/icons-material/Tune';
|
||||
|
||||
import { extractErrorMessage } from '../utils';
|
||||
|
||||
@@ -22,11 +19,9 @@ import * as EMSESP from './api';
|
||||
const HelpInformation: FC = () => {
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const { me } = useContext(AuthenticatedContext);
|
||||
|
||||
const saveFile = (json: any, endpoint: string) => {
|
||||
const a = document.createElement('a');
|
||||
const filename = 'emsesp_' + endpoint + '.json';
|
||||
const filename = 'emsesp_' + endpoint + '.txt';
|
||||
a.href = URL.createObjectURL(
|
||||
new Blob([JSON.stringify(json, null, 2)], {
|
||||
type: 'text/plain'
|
||||
@@ -36,7 +31,7 @@ const HelpInformation: FC = () => {
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
enqueueSnackbar('File downloaded', { variant: 'info' });
|
||||
enqueueSnackbar('System information downloaded', { variant: 'info' });
|
||||
};
|
||||
|
||||
const callAPI = async (endpoint: string) => {
|
||||
@@ -56,60 +51,27 @@ const HelpInformation: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const downloadSettings = async () => {
|
||||
try {
|
||||
const response = await EMSESP.getSettings();
|
||||
if (response.status !== 200) {
|
||||
enqueueSnackbar('Unable to get settings', { variant: 'error' });
|
||||
} else {
|
||||
saveFile(response.data, 'settings');
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
const downloadCustomizations = async () => {
|
||||
try {
|
||||
const response = await EMSESP.getCustomizations();
|
||||
if (response.status !== 200) {
|
||||
enqueueSnackbar('Unable to get customizations', { variant: 'error' });
|
||||
} else {
|
||||
saveFile(response.data, 'customizations');
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SectionContent title="Application Information & Support" titleGutter>
|
||||
<SectionContent title="Support Information" titleGutter>
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<TuneIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
For a help on each of the Application Settings see
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://emsesp.github.io/docs/#/Configure-firmware?id=ems-esp-settings"
|
||||
color="primary"
|
||||
>
|
||||
{'Configuring EMS-ESP'}
|
||||
</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<MenuBookIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
For general information about EMS-ESP visit the online
|
||||
Visit the online
|
||||
<Link target="_blank" href="https://emsesp.github.io/docs" color="primary">
|
||||
{'Documentation'}
|
||||
{'Wiki'}
|
||||
</Link>
|
||||
to get instructions on how to
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://emsesp.github.io/docs/#/Configure-firmware?id=ems-esp-settings"
|
||||
color="primary"
|
||||
>
|
||||
{'configure'}
|
||||
</Link>
|
||||
EMS-ESP and access other information.
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
@@ -122,7 +84,7 @@ const HelpInformation: FC = () => {
|
||||
<Link target="_blank" href="https://discord.gg/3J3GgnzpyT" color="primary">
|
||||
{'Discord'}
|
||||
</Link>
|
||||
server
|
||||
server.
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
@@ -130,69 +92,33 @@ const HelpInformation: FC = () => {
|
||||
<ListItemAvatar>
|
||||
<GitHubIcon />
|
||||
</ListItemAvatar>
|
||||
|
||||
<ListItemText>
|
||||
To report an issue or request a feature, please
|
||||
<Link component="button" variant="body1" onClick={() => callAPI('info')}>
|
||||
download
|
||||
</Link>
|
||||
the debug information and include in a new
|
||||
Submit a
|
||||
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">
|
||||
GitHub issue
|
||||
support issue
|
||||
</Link>
|
||||
for requesting a new feature or reporting a bug.
|
||||
<br />
|
||||
Make sure you also
|
||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => callAPI('info')}>
|
||||
download
|
||||
</Button>
|
||||
and attach your system details for a faster response.
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
{me.admin && (
|
||||
<>
|
||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||
Download Settings
|
||||
</Typography>
|
||||
<Box color="warning.main">
|
||||
<Typography variant="body2">
|
||||
Export the application settings and any customizations to a JSON file. These files can later be uploaded
|
||||
via System→Upload.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => downloadSettings()}
|
||||
>
|
||||
settings
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => downloadCustomizations()}
|
||||
>
|
||||
customizations
|
||||
</Button>
|
||||
</ButtonRow>
|
||||
</Box>
|
||||
<MessageBox
|
||||
my={2}
|
||||
level="warning"
|
||||
message="Be careful when sharing your Settings as the file contains passwords and other sensitive system
|
||||
information!"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Box bgcolor="secondary.info" border={1} p={1} mt={4}>
|
||||
<Typography align="center" variant="h6">
|
||||
EMS-ESP is a free and open-source project.
|
||||
<br></br>Please consider supporting us by giving it a
|
||||
<StarIcon style={{ fontSize: 16, color: '#fdff3a', verticalAlign: 'middle' }} /> on
|
||||
<Box border={1} p={1} mt={4}>
|
||||
<Typography align="center" variant="h6" color="orange">
|
||||
EMS-ESP will always be a free and open-source project
|
||||
<br></br>Please consider supporting it with a
|
||||
<StarIcon style={{ fontSize: 16, color: 'yellow', verticalAlign: 'middle' }} /> on
|
||||
<Link href="https://github.com/emsesp/EMS-ESP32" color="primary">
|
||||
{'GitHub'}
|
||||
</Link>
|
||||
!
|
||||
</Typography>
|
||||
<Typography align="center">@proddy @MichaelDvP</Typography>
|
||||
</Box>
|
||||
</SectionContent>
|
||||
);
|
||||
|
||||
@@ -13,7 +13,8 @@ import {
|
||||
ToggleButtonGroup,
|
||||
Tooltip,
|
||||
Grid,
|
||||
TextField
|
||||
TextField,
|
||||
Link
|
||||
} from '@mui/material';
|
||||
|
||||
import { Table } from '@table-library/react-table-library/table';
|
||||
@@ -26,11 +27,6 @@ import { useSnackbar } from 'notistack';
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
|
||||
// import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||
// import StarIcon from '@mui/icons-material/Star';
|
||||
// import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||
// import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||
|
||||
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
|
||||
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
|
||||
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
|
||||
@@ -48,13 +44,15 @@ import { extractErrorMessage } from '../utils';
|
||||
|
||||
import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types';
|
||||
|
||||
export const APIURL = window.location.origin + '/api/';
|
||||
|
||||
const SettingsCustomization: FC = () => {
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const [deviceEntities, setDeviceEntities] = useState<DeviceEntity[]>([{ id: '', v: 0, n: '', m: 0, w: false }]);
|
||||
const [devices, setDevices] = useState<Devices>();
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
const [selectedDevice, setSelectedDevice] = useState<number>(0);
|
||||
const [selectedDevice, setSelectedDevice] = useState<number>(-1);
|
||||
const [confirmReset, setConfirmReset] = useState<boolean>(false);
|
||||
const [selectedFilters, setSelectedFilters] = useState<number>(0);
|
||||
const [search, setSearch] = useState('');
|
||||
@@ -63,80 +61,59 @@ const SettingsCustomization: FC = () => {
|
||||
const [masks, setMasks] = useState(() => ['']);
|
||||
|
||||
const entities_theme = useTheme({
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: 120px repeat(1, minmax(0, 1fr)) 120px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
.td {
|
||||
height: 32px;
|
||||
min-height: 32px;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
&:last-of-type {
|
||||
text-align: right;
|
||||
}
|
||||
`,
|
||||
HeaderRow: `
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
color: #90CAF9;
|
||||
|
||||
.th {
|
||||
border-bottom: 1px solid #565656;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&:nth-of-type(1) .th {
|
||||
text-align: center;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
background-color: #1e1e1e;
|
||||
position: relative;
|
||||
|
||||
.td {
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
&:not(:first-of-type) {
|
||||
margin-top: -1px;
|
||||
}
|
||||
&:hover {
|
||||
z-index: 2;
|
||||
color: white;
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
},
|
||||
&.tr.tr-body.row-select.row-select-single-selected, &.tr.tr-body.row-select.row-select-selected {
|
||||
|
||||
&.tr.tr-body.row-select.row-select-single-selected {
|
||||
background-color: #3d4752;
|
||||
color: white;
|
||||
font-weight: normal;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
|
||||
&:nth-of-type(odd) .td {
|
||||
background-color: #303030;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
&:not(.stiff) > div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
&:nth-of-type(1) {
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
max-width: 120px;
|
||||
}
|
||||
Cell: `
|
||||
&:nth-of-type(2) {
|
||||
padding-left: 8px;
|
||||
flex: 1;
|
||||
padding: 8px;
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
&:last-of-type {
|
||||
padding-right: 8px;
|
||||
text-align: right;
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
}
|
||||
`,
|
||||
HeaderCell: `
|
||||
&:nth-of-type(1) {
|
||||
padding-left: 24px;
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
padding-left: 0px;
|
||||
}
|
||||
&:not(:last-of-type) {
|
||||
border-right: 1px solid #565656;
|
||||
}
|
||||
`
|
||||
});
|
||||
@@ -209,7 +186,15 @@ const SettingsCustomization: FC = () => {
|
||||
} else if (de.n === '') {
|
||||
return 'Command: ' + de.id;
|
||||
}
|
||||
return de.n + ' (' + de.id + ')';
|
||||
return (
|
||||
<>
|
||||
{de.n} (
|
||||
<Link target="_blank" href={APIURL + devices?.devices[selectedDevice].t + '/' + de.id}>
|
||||
{de.id}
|
||||
</Link>
|
||||
)
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const getMaskNumber = (newMask: string[]) => {
|
||||
@@ -254,20 +239,12 @@ const SettingsCustomization: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
function compareDevices(a: DeviceShort, b: DeviceShort) {
|
||||
if (a.s < b.s) {
|
||||
return -1;
|
||||
}
|
||||
if (a.s > b.s) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const changeSelectedDevice = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (devices) {
|
||||
const selected_device = parseInt(event.target.value, 10);
|
||||
setSelectedDevice(selected_device);
|
||||
fetchDeviceEntities(selected_device);
|
||||
fetchDeviceEntities(devices?.devices[selected_device].i);
|
||||
}
|
||||
};
|
||||
|
||||
const resetCustomization = async () => {
|
||||
@@ -282,7 +259,7 @@ const SettingsCustomization: FC = () => {
|
||||
};
|
||||
|
||||
const saveCustomization = async () => {
|
||||
if (deviceEntities && selectedDevice) {
|
||||
if (devices && deviceEntities && selectedDevice !== -1) {
|
||||
const masked_entities = deviceEntities
|
||||
.filter((de) => de.m !== de.om)
|
||||
.map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id);
|
||||
@@ -294,7 +271,7 @@ const SettingsCustomization: FC = () => {
|
||||
|
||||
try {
|
||||
const response = await EMSESP.writeMaskedEntities({
|
||||
id: selectedDevice,
|
||||
id: devices?.devices[selectedDevice].i,
|
||||
entity_ids: masked_entities
|
||||
});
|
||||
if (response.status === 200) {
|
||||
@@ -320,13 +297,13 @@ const SettingsCustomization: FC = () => {
|
||||
<Typography variant="body2">Select a device and customize each of its entities using the options:</Typography>
|
||||
<Typography variant="body2">
|
||||
<OptionIcon type="favorite" isSet={true} />
|
||||
=mark as a favorite
|
||||
=mark as favorite
|
||||
<OptionIcon type="readonly" isSet={true} />
|
||||
=disable write action
|
||||
<OptionIcon type="api_mqtt_exclude" isSet={true} />
|
||||
=exclude from MQTT and API outputs
|
||||
=exclude from MQTT and API
|
||||
<OptionIcon type="web_exclude" isSet={true} />
|
||||
=hide from Web Dashboard
|
||||
=hide from Dashboard
|
||||
</Typography>
|
||||
</Box>
|
||||
<ValidatedTextField
|
||||
@@ -339,11 +316,11 @@ const SettingsCustomization: FC = () => {
|
||||
margin="normal"
|
||||
select
|
||||
>
|
||||
<MenuItem disabled key={0} value={0}>
|
||||
<MenuItem disabled key={0} value={-1}>
|
||||
Select a device...
|
||||
</MenuItem>
|
||||
{devices.devices.sort(compareDevices).map((device: DeviceShort, index) => (
|
||||
<MenuItem key={index} value={device.i}>
|
||||
{devices.devices.map((device: DeviceShort, index) => (
|
||||
<MenuItem key={index} value={index}>
|
||||
{device.s}
|
||||
</MenuItem>
|
||||
))}
|
||||
@@ -451,7 +428,7 @@ const SettingsCustomization: FC = () => {
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell>OPTIONS</HeaderCell>
|
||||
<HeaderCell stiff>OPTIONS</HeaderCell>
|
||||
<HeaderCell resize>
|
||||
<Button
|
||||
fullWidth
|
||||
@@ -462,13 +439,13 @@ const SettingsCustomization: FC = () => {
|
||||
NAME
|
||||
</Button>
|
||||
</HeaderCell>
|
||||
<HeaderCell>VALUE</HeaderCell>
|
||||
<HeaderCell resize>VALUE</HeaderCell>
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((de: DeviceEntity) => (
|
||||
<Row key={de.id} item={de}>
|
||||
<Cell>
|
||||
<Cell stiff>
|
||||
<ToggleButtonGroup
|
||||
size="small"
|
||||
color="secondary"
|
||||
|
||||
@@ -6,7 +6,6 @@ export interface Settings {
|
||||
syslog_mark_interval: number;
|
||||
syslog_host: string;
|
||||
syslog_port: number;
|
||||
master_thermostat: number;
|
||||
shower_timer: boolean;
|
||||
shower_alert: boolean;
|
||||
shower_alert_coldshot: number;
|
||||
@@ -98,6 +97,7 @@ export interface SensorData {
|
||||
}
|
||||
|
||||
export interface CoreData {
|
||||
connected: boolean;
|
||||
devices: Device[];
|
||||
active_sensors: number;
|
||||
analog_enabled: boolean;
|
||||
@@ -105,9 +105,10 @@ export interface CoreData {
|
||||
|
||||
export interface DeviceShort {
|
||||
i: number; // id
|
||||
d: number; // deviceid
|
||||
p: number; // productid
|
||||
d?: number; // deviceid
|
||||
p?: number; // productid
|
||||
s: string; // shortname
|
||||
t?: string; // device type name
|
||||
}
|
||||
|
||||
export interface Devices {
|
||||
|
||||
@@ -5,4 +5,3 @@ export * from './submit';
|
||||
export * from './time';
|
||||
export * from './useRest';
|
||||
export * from './props';
|
||||
|
||||
|
||||
@@ -71,9 +71,9 @@ static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or mo
|
||||
memset(_buf, 0x00, 16);
|
||||
#ifdef ESP32
|
||||
mbedtls_md5_init(&_ctx);
|
||||
mbedtls_md5_starts(&_ctx);
|
||||
mbedtls_md5_update(&_ctx, data, len);
|
||||
mbedtls_md5_finish(&_ctx, _buf);
|
||||
mbedtls_md5_update_ret (&_ctx,data,len);
|
||||
mbedtls_md5_finish_ret(&_ctx,data);
|
||||
mbedtls_internal_md5_process( &_ctx ,data);
|
||||
#else
|
||||
MD5Init(&_ctx);
|
||||
MD5Update(&_ctx, data, len);
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -1,7 +0,0 @@
|
||||
Copyright 2020 Brian Pugh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,24 +0,0 @@
|
||||
Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
- Neither the name of ARM nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
static constexpr const char LFS_NAME[] = "spiffs";
|
||||
|
||||
#include "vfs_api.h"
|
||||
|
||||
extern "C" {
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include "esp_littlefs.h"
|
||||
}
|
||||
|
||||
#include "LITTLEFS.h"
|
||||
|
||||
using namespace fs;
|
||||
|
||||
LITTLEFSFS::LITTLEFSFS() : FS(FSImplPtr(new VFSImpl()))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool LITTLEFSFS::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFiles)
|
||||
{
|
||||
if(esp_littlefs_mounted(LFS_NAME)){
|
||||
log_w("LITTLEFS Already Mounted!");
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = basePath,
|
||||
.partition_label = LFS_NAME,
|
||||
.format_if_mount_failed = false
|
||||
};
|
||||
|
||||
esp_err_t err = esp_vfs_littlefs_register(&conf);
|
||||
if(err == ESP_FAIL && formatOnFail){
|
||||
if(format()){
|
||||
err = esp_vfs_littlefs_register(&conf);
|
||||
}
|
||||
}
|
||||
if(err != ESP_OK){
|
||||
log_e("Mounting LITTLEFS failed! Error: %d", err);
|
||||
return false;
|
||||
}
|
||||
_impl->mountpoint(basePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LITTLEFSFS::end()
|
||||
{
|
||||
if(esp_littlefs_mounted(LFS_NAME)){
|
||||
esp_err_t err = esp_vfs_littlefs_unregister(LFS_NAME);
|
||||
if(err){
|
||||
log_e("Unmounting LITTLEFS failed! Error: %d", err);
|
||||
return;
|
||||
}
|
||||
_impl->mountpoint(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool LITTLEFSFS::format()
|
||||
{
|
||||
disableCore0WDT();
|
||||
esp_err_t err = esp_littlefs_format(LFS_NAME);
|
||||
enableCore0WDT();
|
||||
if(err){
|
||||
log_e("Formatting LITTLEFS failed! Error: %d", err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t LITTLEFSFS::totalBytes()
|
||||
{
|
||||
size_t total,used;
|
||||
if(esp_littlefs_info(LFS_NAME, &total, &used)){
|
||||
return 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t LITTLEFSFS::usedBytes()
|
||||
{
|
||||
size_t total,used;
|
||||
if(esp_littlefs_info(LFS_NAME, &total, &used)){
|
||||
return 0;
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
LITTLEFSFS LITTLEFS;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef _LITTLEFS_H_
|
||||
#define _LITTLEFS_H_
|
||||
|
||||
#include "FS.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
||||
class LITTLEFSFS : public FS
|
||||
{
|
||||
public:
|
||||
LITTLEFSFS();
|
||||
bool begin(bool formatOnFail=false, const char * basePath="/littlefs", uint8_t maxOpenFiles=5);
|
||||
bool format();
|
||||
size_t totalBytes();
|
||||
size_t usedBytes();
|
||||
void end();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern fs::LITTLEFSFS LITTLEFS;
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,118 +0,0 @@
|
||||
#ifndef ESP_LITTLEFS_H__
|
||||
#define ESP_LITTLEFS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/reent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/poll.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "lfs.h" //#include "littlefs/lfs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Last Modified Time
|
||||
*
|
||||
* Use 't' for LITTLEFS_ATTR_MTIME to match example:
|
||||
* https://github.com/ARMmbed/littlefs/issues/23#issuecomment-482293539
|
||||
* And to match other external tools such as:
|
||||
* https://github.com/earlephilhower/mklittlefs
|
||||
*/
|
||||
#define LITTLEFS_ATTR_MTIME ((uint8_t) 't')
|
||||
|
||||
/**
|
||||
*Configuration structure for esp_vfs_littlefs_register.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *base_path; /**< Mounting point. */
|
||||
const char *partition_label; /**< Label of partition to use. */
|
||||
uint8_t format_if_mount_failed:1; /**< Format the file system if it fails to mount. */
|
||||
uint8_t dont_mount:1; /**< Don't attempt to mount or format. Overrides format_if_mount_failed */
|
||||
} esp_vfs_littlefs_conf_t;
|
||||
|
||||
/**
|
||||
* Register and mount littlefs to VFS with given path prefix.
|
||||
*
|
||||
* @param conf Pointer to esp_vfs_littlefs_conf_t configuration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - ESP_ERR_NO_MEM if objects could not be allocated
|
||||
* - ESP_ERR_INVALID_STATE if already mounted or partition is encrypted
|
||||
* - ESP_ERR_NOT_FOUND if partition for littlefs was not found
|
||||
* - ESP_FAIL if mount or format fails
|
||||
*/
|
||||
esp_err_t esp_vfs_littlefs_register(const esp_vfs_littlefs_conf_t * conf);
|
||||
|
||||
/**
|
||||
* Unregister and unmount littlefs from VFS
|
||||
*
|
||||
* @param partition_label Label of the partition to unregister.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_ERR_INVALID_STATE already unregistered
|
||||
*/
|
||||
esp_err_t esp_vfs_littlefs_unregister(const char* partition_label);
|
||||
|
||||
/**
|
||||
* Check if littlefs is mounted
|
||||
*
|
||||
* @param partition_label Label of the partition to check.
|
||||
*
|
||||
* @return
|
||||
* - true if mounted
|
||||
* - false if not mounted
|
||||
*/
|
||||
bool esp_littlefs_mounted(const char* partition_label);
|
||||
|
||||
/**
|
||||
* Format the littlefs partition
|
||||
*
|
||||
* @param partition_label Label of the partition to format.
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t esp_littlefs_format(const char* partition_label);
|
||||
|
||||
/**
|
||||
* Get information for littlefs
|
||||
*
|
||||
* @param partition_label Optional, label of the partition to get info for.
|
||||
* @param[out] total_bytes Size of the file system
|
||||
* @param[out] used_bytes Current used bytes in the file system
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - ESP_ERR_INVALID_STATE if not mounted
|
||||
*/
|
||||
esp_err_t esp_littlefs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes);
|
||||
|
||||
#if CONFIG_LITTLEFS_HUMAN_READABLE
|
||||
/**
|
||||
* @brief converts an enumerated lfs error into a string.
|
||||
* @param lfs_errno The enumerated littlefs error.
|
||||
*/
|
||||
const char * esp_littlefs_errno(enum lfs_error lfs_errno);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,695 +0,0 @@
|
||||
/*
|
||||
* The little filesystem
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef LFS_H
|
||||
#define LFS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lfs_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
/// Version info ///
|
||||
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS_VERSION 0x00020004
|
||||
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
|
||||
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
|
||||
|
||||
// Version of On-disk data structures
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS_DISK_VERSION 0x00020000
|
||||
#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16))
|
||||
#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0))
|
||||
|
||||
|
||||
/// Definitions ///
|
||||
|
||||
// Type definitions
|
||||
typedef uint32_t lfs_size_t;
|
||||
typedef uint32_t lfs_off_t;
|
||||
|
||||
typedef int32_t lfs_ssize_t;
|
||||
typedef int32_t lfs_soff_t;
|
||||
|
||||
typedef uint32_t lfs_block_t;
|
||||
|
||||
// Maximum name size in bytes, may be redefined to reduce the size of the
|
||||
// info struct. Limited to <= 1022. Stored in superblock and must be
|
||||
// respected by other littlefs drivers.
|
||||
#ifndef LFS_NAME_MAX
|
||||
#define LFS_NAME_MAX 255
|
||||
#endif
|
||||
|
||||
// Maximum size of a file in bytes, may be redefined to limit to support other
|
||||
// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
|
||||
// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return
|
||||
// incorrect values due to using signed integers. Stored in superblock and
|
||||
// must be respected by other littlefs drivers.
|
||||
#ifndef LFS_FILE_MAX
|
||||
#define LFS_FILE_MAX 2147483647
|
||||
#endif
|
||||
|
||||
// Maximum size of custom attributes in bytes, may be redefined, but there is
|
||||
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
|
||||
#ifndef LFS_ATTR_MAX
|
||||
#define LFS_ATTR_MAX 1022
|
||||
#endif
|
||||
|
||||
// Possible error codes, these are negative to allow
|
||||
// valid positive return values
|
||||
enum lfs_error {
|
||||
LFS_ERR_OK = 0, // No error
|
||||
LFS_ERR_IO = -5, // Error during device operation
|
||||
LFS_ERR_CORRUPT = -84, // Corrupted
|
||||
LFS_ERR_NOENT = -2, // No directory entry
|
||||
LFS_ERR_EXIST = -17, // Entry already exists
|
||||
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
LFS_ERR_BADF = -9, // Bad file number
|
||||
LFS_ERR_FBIG = -27, // File too large
|
||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||
LFS_ERR_NOSPC = -28, // No space left on device
|
||||
LFS_ERR_NOMEM = -12, // No more memory available
|
||||
LFS_ERR_NOATTR = -61, // No data/attr available
|
||||
LFS_ERR_NAMETOOLONG = -36, // File name too long
|
||||
};
|
||||
|
||||
// File types
|
||||
enum lfs_type {
|
||||
// file types
|
||||
LFS_TYPE_REG = 0x001,
|
||||
LFS_TYPE_DIR = 0x002,
|
||||
|
||||
// internally used types
|
||||
LFS_TYPE_SPLICE = 0x400,
|
||||
LFS_TYPE_NAME = 0x000,
|
||||
LFS_TYPE_STRUCT = 0x200,
|
||||
LFS_TYPE_USERATTR = 0x300,
|
||||
LFS_TYPE_FROM = 0x100,
|
||||
LFS_TYPE_TAIL = 0x600,
|
||||
LFS_TYPE_GLOBALS = 0x700,
|
||||
LFS_TYPE_CRC = 0x500,
|
||||
|
||||
// internally used type specializations
|
||||
LFS_TYPE_CREATE = 0x401,
|
||||
LFS_TYPE_DELETE = 0x4ff,
|
||||
LFS_TYPE_SUPERBLOCK = 0x0ff,
|
||||
LFS_TYPE_DIRSTRUCT = 0x200,
|
||||
LFS_TYPE_CTZSTRUCT = 0x202,
|
||||
LFS_TYPE_INLINESTRUCT = 0x201,
|
||||
LFS_TYPE_SOFTTAIL = 0x600,
|
||||
LFS_TYPE_HARDTAIL = 0x601,
|
||||
LFS_TYPE_MOVESTATE = 0x7ff,
|
||||
|
||||
// internal chip sources
|
||||
LFS_FROM_NOOP = 0x000,
|
||||
LFS_FROM_MOVE = 0x101,
|
||||
LFS_FROM_USERATTRS = 0x102,
|
||||
};
|
||||
|
||||
// File open flags
|
||||
enum lfs_open_flags {
|
||||
// open flags
|
||||
LFS_O_RDONLY = 1, // Open a file as read only
|
||||
#ifndef LFS_READONLY
|
||||
LFS_O_WRONLY = 2, // Open a file as write only
|
||||
LFS_O_RDWR = 3, // Open a file as read and write
|
||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
#endif
|
||||
|
||||
// internally used flags
|
||||
#ifndef LFS_READONLY
|
||||
LFS_F_DIRTY = 0x010000, // File does not match storage
|
||||
LFS_F_WRITING = 0x020000, // File has been written since last flush
|
||||
#endif
|
||||
LFS_F_READING = 0x040000, // File has been read since last flush
|
||||
#ifndef LFS_READONLY
|
||||
LFS_F_ERRED = 0x080000, // An error occurred during write
|
||||
#endif
|
||||
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
|
||||
};
|
||||
|
||||
// File seek flags
|
||||
enum lfs_whence_flags {
|
||||
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
||||
};
|
||||
|
||||
|
||||
// Configuration provided during initialization of the littlefs
|
||||
struct lfs_config {
|
||||
// Opaque user provided context that can be used to pass
|
||||
// information to the block device operations
|
||||
void *context;
|
||||
|
||||
// Read a region in a block. Negative error codes are propogated
|
||||
// to the user.
|
||||
int (*read)(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*prog)(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*erase)(const struct lfs_config *c, lfs_block_t block);
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*sync)(const struct lfs_config *c);
|
||||
|
||||
#ifdef LFS_THREADSAFE
|
||||
// Lock the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*lock)(const struct lfs_config *c);
|
||||
|
||||
// Unlock the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*unlock)(const struct lfs_config *c);
|
||||
#endif
|
||||
|
||||
// Minimum size of a block read. All read operations will be a
|
||||
// multiple of this value.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a block program. All program operations will be a
|
||||
// multiple of this value.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erasable block. This does not impact ram consumption and
|
||||
// may be larger than the physical erase size. However, non-inlined files
|
||||
// take up at minimum one block. Must be a multiple of the read
|
||||
// and program sizes.
|
||||
lfs_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device.
|
||||
lfs_size_t block_count;
|
||||
|
||||
// Number of erase cycles before littlefs evicts metadata logs and moves
|
||||
// the metadata to another block. Suggested values are in the
|
||||
// range 100-1000, with large values having better performance at the cost
|
||||
// of less consistent wear distribution.
|
||||
//
|
||||
// Set to -1 to disable block-level wear-leveling.
|
||||
int32_t block_cycles;
|
||||
|
||||
// Size of block caches. Each cache buffers a portion of a block in RAM.
|
||||
// The littlefs needs a read cache, a program cache, and one additional
|
||||
// cache per file. Larger caches can improve performance by storing more
|
||||
// data and reducing the number of disk accesses. Must be a multiple of
|
||||
// the read and program sizes, and a factor of the block size.
|
||||
lfs_size_t cache_size;
|
||||
|
||||
// Size of the lookahead buffer in bytes. A larger lookahead buffer
|
||||
// increases the number of blocks found during an allocation pass. The
|
||||
// lookahead buffer is stored as a compact bitmap, so each byte of RAM
|
||||
// can track 8 blocks. Must be a multiple of 8.
|
||||
lfs_size_t lookahead_size;
|
||||
|
||||
// Optional statically allocated read buffer. Must be cache_size.
|
||||
// By default lfs_malloc is used to allocate this buffer.
|
||||
void *read_buffer;
|
||||
|
||||
// Optional statically allocated program buffer. Must be cache_size.
|
||||
// By default lfs_malloc is used to allocate this buffer.
|
||||
void *prog_buffer;
|
||||
|
||||
// Optional statically allocated lookahead buffer. Must be lookahead_size
|
||||
// and aligned to a 32-bit boundary. By default lfs_malloc is used to
|
||||
// allocate this buffer.
|
||||
void *lookahead_buffer;
|
||||
|
||||
// Optional upper limit on length of file names in bytes. No downside for
|
||||
// larger names except the size of the info struct which is controlled by
|
||||
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
|
||||
// superblock and must be respected by other littlefs drivers.
|
||||
lfs_size_t name_max;
|
||||
|
||||
// Optional upper limit on files in bytes. No downside for larger files
|
||||
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
|
||||
// in superblock and must be respected by other littlefs drivers.
|
||||
lfs_size_t file_max;
|
||||
|
||||
// Optional upper limit on custom attributes in bytes. No downside for
|
||||
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
||||
// LFS_ATTR_MAX when zero.
|
||||
lfs_size_t attr_max;
|
||||
|
||||
// Optional upper limit on total space given to metadata pairs in bytes. On
|
||||
// devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
|
||||
// can help bound the metadata compaction time. Must be <= block_size.
|
||||
// Defaults to block_size when zero.
|
||||
lfs_size_t metadata_max;
|
||||
};
|
||||
|
||||
// File info structure
|
||||
struct lfs_info {
|
||||
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
|
||||
uint8_t type;
|
||||
|
||||
// Size of the file, only valid for REG files. Limited to 32-bits.
|
||||
lfs_size_t size;
|
||||
|
||||
// Name of the file stored as a null-terminated string. Limited to
|
||||
// LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
|
||||
// reduce RAM. LFS_NAME_MAX is stored in superblock and must be
|
||||
// respected by other littlefs drivers.
|
||||
char name[LFS_NAME_MAX+1];
|
||||
};
|
||||
|
||||
// Custom attribute structure, used to describe custom attributes
|
||||
// committed atomically during file writes.
|
||||
struct lfs_attr {
|
||||
// 8-bit type of attribute, provided by user and used to
|
||||
// identify the attribute
|
||||
uint8_t type;
|
||||
|
||||
// Pointer to buffer containing the attribute
|
||||
void *buffer;
|
||||
|
||||
// Size of attribute in bytes, limited to LFS_ATTR_MAX
|
||||
lfs_size_t size;
|
||||
};
|
||||
|
||||
// Optional configuration provided during lfs_file_opencfg
|
||||
struct lfs_file_config {
|
||||
// Optional statically allocated file buffer. Must be cache_size.
|
||||
// By default lfs_malloc is used to allocate this buffer.
|
||||
void *buffer;
|
||||
|
||||
// Optional list of custom attributes related to the file. If the file
|
||||
// is opened with read access, these attributes will be read from disk
|
||||
// during the open call. If the file is opened with write access, the
|
||||
// attributes will be written to disk every file sync or close. This
|
||||
// write occurs atomically with update to the file's contents.
|
||||
//
|
||||
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
|
||||
// than the buffer, it will be padded with zeros. If the stored attribute
|
||||
// is larger, then it will be silently truncated. If the attribute is not
|
||||
// found, it will be created implicitly.
|
||||
struct lfs_attr *attrs;
|
||||
|
||||
// Number of custom attributes in the list
|
||||
lfs_size_t attr_count;
|
||||
};
|
||||
|
||||
|
||||
/// internal littlefs data structures ///
|
||||
typedef struct lfs_cache {
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
lfs_size_t size;
|
||||
uint8_t *buffer;
|
||||
} lfs_cache_t;
|
||||
|
||||
typedef struct lfs_mdir {
|
||||
lfs_block_t pair[2];
|
||||
uint32_t rev;
|
||||
lfs_off_t off;
|
||||
uint32_t etag;
|
||||
uint16_t count;
|
||||
bool erased;
|
||||
bool split;
|
||||
lfs_block_t tail[2];
|
||||
} lfs_mdir_t;
|
||||
|
||||
// littlefs directory type
|
||||
typedef struct lfs_dir {
|
||||
struct lfs_dir *next;
|
||||
uint16_t id;
|
||||
uint8_t type;
|
||||
lfs_mdir_t m;
|
||||
|
||||
lfs_off_t pos;
|
||||
lfs_block_t head[2];
|
||||
} lfs_dir_t;
|
||||
|
||||
// littlefs file type
|
||||
typedef struct lfs_file {
|
||||
struct lfs_file *next;
|
||||
uint16_t id;
|
||||
uint8_t type;
|
||||
lfs_mdir_t m;
|
||||
|
||||
struct lfs_ctz {
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
} ctz;
|
||||
|
||||
uint32_t flags;
|
||||
lfs_off_t pos;
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
lfs_cache_t cache;
|
||||
|
||||
const struct lfs_file_config *cfg;
|
||||
} lfs_file_t;
|
||||
|
||||
typedef struct lfs_superblock {
|
||||
uint32_t version;
|
||||
lfs_size_t block_size;
|
||||
lfs_size_t block_count;
|
||||
lfs_size_t name_max;
|
||||
lfs_size_t file_max;
|
||||
lfs_size_t attr_max;
|
||||
} lfs_superblock_t;
|
||||
|
||||
typedef struct lfs_gstate {
|
||||
uint32_t tag;
|
||||
lfs_block_t pair[2];
|
||||
} lfs_gstate_t;
|
||||
|
||||
// The littlefs filesystem type
|
||||
typedef struct lfs {
|
||||
lfs_cache_t rcache;
|
||||
lfs_cache_t pcache;
|
||||
|
||||
lfs_block_t root[2];
|
||||
struct lfs_mlist {
|
||||
struct lfs_mlist *next;
|
||||
uint16_t id;
|
||||
uint8_t type;
|
||||
lfs_mdir_t m;
|
||||
} *mlist;
|
||||
uint32_t seed;
|
||||
|
||||
lfs_gstate_t gstate;
|
||||
lfs_gstate_t gdisk;
|
||||
lfs_gstate_t gdelta;
|
||||
|
||||
struct lfs_free {
|
||||
lfs_block_t off;
|
||||
lfs_block_t size;
|
||||
lfs_block_t i;
|
||||
lfs_block_t ack;
|
||||
uint32_t *buffer;
|
||||
} free;
|
||||
|
||||
const struct lfs_config *cfg;
|
||||
lfs_size_t name_max;
|
||||
lfs_size_t file_max;
|
||||
lfs_size_t attr_max;
|
||||
|
||||
#ifdef LFS_MIGRATE
|
||||
struct lfs1 *lfs1;
|
||||
#endif
|
||||
} lfs_t;
|
||||
|
||||
|
||||
/// Filesystem functions ///
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Format a block device with the littlefs
|
||||
//
|
||||
// Requires a littlefs object and config struct. This clobbers the littlefs
|
||||
// object, and does not leave the filesystem mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_format(lfs_t *lfs, const struct lfs_config *config);
|
||||
#endif
|
||||
|
||||
// Mounts a littlefs
|
||||
//
|
||||
// Requires a littlefs object and config struct. Multiple filesystems
|
||||
// may be mounted simultaneously with multiple littlefs objects. Both
|
||||
// lfs and config must be allocated while mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
|
||||
|
||||
// Unmounts a littlefs
|
||||
//
|
||||
// Does nothing besides releasing any allocated resources.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_unmount(lfs_t *lfs);
|
||||
|
||||
/// General operations ///
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Removes a file or directory
|
||||
//
|
||||
// If removing a directory, the directory must be empty.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_remove(lfs_t *lfs, const char *path);
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Rename or move a file or directory
|
||||
//
|
||||
// If the destination exists, it must match the source in type.
|
||||
// If the destination is a directory, the directory must be empty.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
|
||||
#endif
|
||||
|
||||
// Find info about a file or directory
|
||||
//
|
||||
// Fills out the info structure, based on the specified file or directory.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
|
||||
|
||||
// Get a custom attribute
|
||||
//
|
||||
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
|
||||
// the buffer, it will be padded with zeros. If the stored attribute is larger,
|
||||
// then it will be silently truncated. If no attribute is found, the error
|
||||
// LFS_ERR_NOATTR is returned and the buffer is filled with zeros.
|
||||
//
|
||||
// Returns the size of the attribute, or a negative error code on failure.
|
||||
// Note, the returned size is the size of the attribute on disk, irrespective
|
||||
// of the size of the buffer. This can be used to dynamically allocate a buffer
|
||||
// or check for existance.
|
||||
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
|
||||
uint8_t type, void *buffer, lfs_size_t size);
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Set custom attributes
|
||||
//
|
||||
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||
// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be
|
||||
// implicitly created.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_setattr(lfs_t *lfs, const char *path,
|
||||
uint8_t type, const void *buffer, lfs_size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Removes a custom attribute
|
||||
//
|
||||
// If an attribute is not found, nothing happens.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
|
||||
#endif
|
||||
|
||||
|
||||
/// File operations ///
|
||||
|
||||
// Open a file
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
// are values from the enum lfs_open_flags that are bitwise-ored together.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
|
||||
const char *path, int flags);
|
||||
|
||||
// Open a file with extra configuration
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
// are values from the enum lfs_open_flags that are bitwise-ored together.
|
||||
//
|
||||
// The config struct provides additional config options per file as described
|
||||
// above. The config struct must be allocated while the file is open, and the
|
||||
// config struct must be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
||||
const char *path, int flags,
|
||||
const struct lfs_file_config *config);
|
||||
|
||||
// Close a file
|
||||
//
|
||||
// Any pending writes are written out to storage as though
|
||||
// sync had been called and releases any allocated resources.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Synchronize a file on storage
|
||||
//
|
||||
// Any pending writes are written out to storage.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Read data from file
|
||||
//
|
||||
// Takes a buffer and size indicating where to store the read data.
|
||||
// Returns the number of bytes read, or a negative error code on failure.
|
||||
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
|
||||
void *buffer, lfs_size_t size);
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Write data to file
|
||||
//
|
||||
// Takes a buffer and size indicating the data to write. The file will not
|
||||
// actually be updated on the storage until either sync or close is called.
|
||||
//
|
||||
// Returns the number of bytes written, or a negative error code on failure.
|
||||
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
|
||||
const void *buffer, lfs_size_t size);
|
||||
#endif
|
||||
|
||||
// Change the position of the file
|
||||
//
|
||||
// The change in position is determined by the offset and whence flag.
|
||||
// Returns the new position of the file, or a negative error code on failure.
|
||||
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
|
||||
lfs_soff_t off, int whence);
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Truncates the size of the file to the specified size
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
|
||||
#endif
|
||||
|
||||
// Return the position of the file
|
||||
//
|
||||
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
|
||||
// Returns the position of the file, or a negative error code on failure.
|
||||
lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Change the position of the file to the beginning of the file
|
||||
//
|
||||
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET)
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Return the size of the file
|
||||
//
|
||||
// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
|
||||
// Returns the size of the file, or a negative error code on failure.
|
||||
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
|
||||
/// Directory operations ///
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Create a directory
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_mkdir(lfs_t *lfs, const char *path);
|
||||
#endif
|
||||
|
||||
// Open a directory
|
||||
//
|
||||
// Once open a directory can be used with read to iterate over files.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
|
||||
|
||||
// Close a directory
|
||||
//
|
||||
// Releases any allocated resources.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
// Read an entry in the directory
|
||||
//
|
||||
// Fills out the info structure, based on the specified file or directory.
|
||||
// Returns a positive value on success, 0 at the end of directory,
|
||||
// or a negative error code on failure.
|
||||
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
|
||||
|
||||
// Change the position of the directory
|
||||
//
|
||||
// The new off must be a value previous returned from tell and specifies
|
||||
// an absolute offset in the directory seek.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
|
||||
|
||||
// Return the position of the directory
|
||||
//
|
||||
// The returned offset is only meant to be consumed by seek and may not make
|
||||
// sense, but does indicate the current position in the directory iteration.
|
||||
//
|
||||
// Returns the position of the directory, or a negative error code on failure.
|
||||
lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
// Change the position of the directory to the beginning of the directory
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
|
||||
/// Filesystem-level filesystem operations
|
||||
|
||||
// Finds the current size of the filesystem
|
||||
//
|
||||
// Note: Result is best effort. If files share COW structures, the returned
|
||||
// size may be larger than the filesystem actually is.
|
||||
//
|
||||
// Returns the number of allocated blocks, or a negative error code on failure.
|
||||
lfs_ssize_t lfs_fs_size(lfs_t *lfs);
|
||||
|
||||
// Traverse through all blocks in use by the filesystem
|
||||
//
|
||||
// The provided callback will be called with each block address that is
|
||||
// currently in use by the filesystem. This can be used to determine which
|
||||
// blocks are in use or how much of the storage is available.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
#ifdef LFS_MIGRATE
|
||||
// Attempts to migrate a previous version of littlefs
|
||||
//
|
||||
// Behaves similarly to the lfs_format function. Attempts to mount
|
||||
// the previous version of littlefs and update the filesystem so it can be
|
||||
// mounted with the current version of littlefs.
|
||||
//
|
||||
// Requires a littlefs object and config struct. This clobbers the littlefs
|
||||
// object, and does not leave the filesystem mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* lfs util functions
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include "lfs_util.h"
|
||||
|
||||
// Only compile if user does not provide custom config
|
||||
#ifndef LFS_CONFIG
|
||||
|
||||
|
||||
// Software CRC implementation with small lookup table
|
||||
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
|
||||
static const uint32_t rtable[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
||||
};
|
||||
|
||||
const uint8_t *data = buffer;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
|
||||
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* lfs utility functions
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef LFS_UTIL_H
|
||||
#define LFS_UTIL_H
|
||||
|
||||
// Users can override lfs_util.h with their own configuration by defining
|
||||
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
|
||||
//
|
||||
// If LFS_CONFIG is used, none of the default utils will be emitted and must be
|
||||
// provided by the config file. To start, I would suggest copying lfs_util.h
|
||||
// and modifying as needed.
|
||||
#ifdef LFS_CONFIG
|
||||
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
|
||||
#define LFS_STRINGIZE2(x) #x
|
||||
#include LFS_STRINGIZE(LFS_CONFIG)
|
||||
#else
|
||||
|
||||
// System includes
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifndef LFS_NO_MALLOC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifndef LFS_NO_ASSERT
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#if !defined(LFS_NO_DEBUG) || \
|
||||
!defined(LFS_NO_WARN) || \
|
||||
!defined(LFS_NO_ERROR) || \
|
||||
defined(LFS_YES_TRACE)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
// Macros, may be replaced by system specific wrappers. Arguments to these
|
||||
// macros must not have side-effects as the macros can be removed for a smaller
|
||||
// code footprint
|
||||
|
||||
// Logging functions
|
||||
#ifndef LFS_TRACE
|
||||
#ifdef LFS_YES_TRACE
|
||||
#define LFS_TRACE_(fmt, ...) \
|
||||
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS_TRACE(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LFS_DEBUG
|
||||
#ifndef LFS_NO_DEBUG
|
||||
#define LFS_DEBUG_(fmt, ...) \
|
||||
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS_DEBUG(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LFS_WARN
|
||||
#ifndef LFS_NO_WARN
|
||||
#define LFS_WARN_(fmt, ...) \
|
||||
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS_WARN(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LFS_ERROR
|
||||
#ifndef LFS_NO_ERROR
|
||||
#define LFS_ERROR_(fmt, ...) \
|
||||
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS_ERROR(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Runtime assertions
|
||||
#ifndef LFS_ASSERT
|
||||
#ifndef LFS_NO_ASSERT
|
||||
#define LFS_ASSERT(test) assert(test)
|
||||
#else
|
||||
#define LFS_ASSERT(test)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// Builtin functions, these may be replaced by more efficient
|
||||
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
|
||||
// expensive basic C implementation for debugging purposes
|
||||
|
||||
// Min/max functions for unsigned 32-bit numbers
|
||||
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
// Align to nearest multiple of a size
|
||||
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
|
||||
return a - (a % alignment);
|
||||
}
|
||||
|
||||
static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
|
||||
return lfs_aligndown(a + alignment-1, alignment);
|
||||
}
|
||||
|
||||
// Find the smallest power of 2 greater than or equal to a
|
||||
static inline uint32_t lfs_npw2(uint32_t a) {
|
||||
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return 32 - __builtin_clz(a-1);
|
||||
#else
|
||||
uint32_t r = 0;
|
||||
uint32_t s;
|
||||
a -= 1;
|
||||
s = (a > 0xffff) << 4; a >>= s; r |= s;
|
||||
s = (a > 0xff ) << 3; a >>= s; r |= s;
|
||||
s = (a > 0xf ) << 2; a >>= s; r |= s;
|
||||
s = (a > 0x3 ) << 1; a >>= s; r |= s;
|
||||
return (r | (a >> 1)) + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of trailing binary zeros in a
|
||||
// lfs_ctz(0) may be undefined
|
||||
static inline uint32_t lfs_ctz(uint32_t a) {
|
||||
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
|
||||
return __builtin_ctz(a);
|
||||
#else
|
||||
return lfs_npw2((a & -a) + 1) - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of binary ones in a
|
||||
static inline uint32_t lfs_popc(uint32_t a) {
|
||||
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return __builtin_popcount(a);
|
||||
#else
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Find the sequence comparison of a and b, this is the distance
|
||||
// between a and b ignoring overflow
|
||||
static inline int lfs_scmp(uint32_t a, uint32_t b) {
|
||||
return (int)(unsigned)(a - b);
|
||||
}
|
||||
|
||||
// Convert between 32-bit little-endian and native order
|
||||
static inline uint32_t lfs_fromle32(uint32_t a) {
|
||||
#if !defined(LFS_NO_INTRINSICS) && ( \
|
||||
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
return a;
|
||||
#elif !defined(LFS_NO_INTRINSICS) && ( \
|
||||
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
return __builtin_bswap32(a);
|
||||
#else
|
||||
return (((uint8_t*)&a)[0] << 0) |
|
||||
(((uint8_t*)&a)[1] << 8) |
|
||||
(((uint8_t*)&a)[2] << 16) |
|
||||
(((uint8_t*)&a)[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t lfs_tole32(uint32_t a) {
|
||||
return lfs_fromle32(a);
|
||||
}
|
||||
|
||||
// Convert between 32-bit big-endian and native order
|
||||
static inline uint32_t lfs_frombe32(uint32_t a) {
|
||||
#if !defined(LFS_NO_INTRINSICS) && ( \
|
||||
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
return __builtin_bswap32(a);
|
||||
#elif !defined(LFS_NO_INTRINSICS) && ( \
|
||||
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
return a;
|
||||
#else
|
||||
return (((uint8_t*)&a)[0] << 24) |
|
||||
(((uint8_t*)&a)[1] << 16) |
|
||||
(((uint8_t*)&a)[2] << 8) |
|
||||
(((uint8_t*)&a)[3] << 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t lfs_tobe32(uint32_t a) {
|
||||
return lfs_frombe32(a);
|
||||
}
|
||||
|
||||
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
|
||||
|
||||
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
// Note, memory must be 64-bit aligned
|
||||
static inline void *lfs_malloc(size_t size) {
|
||||
#ifndef LFS_NO_MALLOC
|
||||
return malloc(size);
|
||||
#else
|
||||
(void)size;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void lfs_free(void *p) {
|
||||
#ifndef LFS_NO_MALLOC
|
||||
free(p);
|
||||
#else
|
||||
(void)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* @file littlefs_api.c
|
||||
* @brief Maps the HAL of esp_partition <-> littlefs
|
||||
* @author Brian Pugh
|
||||
*/
|
||||
|
||||
#define ESP_LOCAL_LOG_LEVEL ESP_LOG_INFO
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "lfs.h"
|
||||
#include "esp_littlefs.h"
|
||||
#include "littlefs_api.h"
|
||||
|
||||
static const char TAG[] = "esp_littlefs_api";
|
||||
|
||||
int littlefs_api_read(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, void *buffer, lfs_size_t size) {
|
||||
esp_littlefs_t * efs = c->context;
|
||||
size_t part_off = (block * c->block_size) + off;
|
||||
esp_err_t err = esp_partition_read(efs->partition, part_off, buffer, size);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", part_off, size, err);
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int littlefs_api_prog(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, const void *buffer, lfs_size_t size) {
|
||||
esp_littlefs_t * efs = c->context;
|
||||
size_t part_off = (block * c->block_size) + off;
|
||||
esp_err_t err = esp_partition_write(efs->partition, part_off, buffer, size);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", part_off, size, err);
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int littlefs_api_erase(const struct lfs_config *c, lfs_block_t block) {
|
||||
esp_littlefs_t * efs = c->context;
|
||||
size_t part_off = block * c->block_size;
|
||||
esp_err_t err = esp_partition_erase_range(efs->partition, part_off, c->block_size);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", part_off, c->block_size, err);
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int littlefs_api_sync(const struct lfs_config *c) {
|
||||
/* Unnecessary for esp-idf */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
#ifndef ESP_LITTLEFS_API_H__
|
||||
#define ESP_LITTLEFS_API_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_partition.h"
|
||||
#include "lfs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief a file descriptor
|
||||
* That's also a singly linked list used for keeping tracks of all opened file descriptor
|
||||
*
|
||||
* Shortcomings/potential issues of 32-bit hash (when CONFIG_LITTLEFS_USE_ONLY_HASH) listed here:
|
||||
* * unlink - If a different file is open that generates a hash collision, it will report an
|
||||
* error that it cannot unlink an open file.
|
||||
* * rename - If a different file is open that generates a hash collision with
|
||||
* src or dst, it will report an error that it cannot rename an open file.
|
||||
* Potential consequences:
|
||||
* 1. A file cannot be deleted while a collision-geneating file is open.
|
||||
* Worst-case, if the other file is always open during the lifecycle
|
||||
* of your app, it's collision file cannot be deleted, which in the
|
||||
* worst-case could cause storage-capacity issues.
|
||||
* 2. Same as (1), but for renames
|
||||
*/
|
||||
typedef struct _vfs_littlefs_file_t {
|
||||
lfs_file_t file;
|
||||
uint32_t hash;
|
||||
struct _vfs_littlefs_file_t * next; /*!< Pointer to next file in Singly Linked List */
|
||||
#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH
|
||||
char * path;
|
||||
#endif
|
||||
} vfs_littlefs_file_t;
|
||||
|
||||
/**
|
||||
* @brief littlefs definition structure
|
||||
*/
|
||||
typedef struct {
|
||||
lfs_t *fs; /*!< Handle to the underlying littlefs */
|
||||
SemaphoreHandle_t lock; /*!< FS lock */
|
||||
const esp_partition_t* partition; /*!< The partition on which littlefs is located */
|
||||
char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */
|
||||
|
||||
struct lfs_config cfg; /*!< littlefs Mount configuration */
|
||||
|
||||
vfs_littlefs_file_t *file; /*!< Singly Linked List of files */
|
||||
|
||||
vfs_littlefs_file_t **cache; /*!< A cache of pointers to the opened files */
|
||||
uint16_t cache_size; /*!< The cache allocated size (in pointers) */
|
||||
uint16_t fd_count; /*!< The count of opened file descriptor used to speed up computation */
|
||||
} esp_littlefs_t;
|
||||
|
||||
/**
|
||||
* @brief Read a region in a block.
|
||||
*
|
||||
* Negative error codes are propogated to the user.
|
||||
*
|
||||
* @return errorcode. 0 on success.
|
||||
*/
|
||||
int littlefs_api_read(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
|
||||
/**
|
||||
* @brief Program a region in a block.
|
||||
*
|
||||
* The block must have previously been erased.
|
||||
* Negative error codes are propogated to the user.
|
||||
* May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
*
|
||||
* @return errorcode. 0 on success.
|
||||
*/
|
||||
int littlefs_api_prog(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
|
||||
/**
|
||||
* @brief Erase a block.
|
||||
*
|
||||
* A block must be erased before being programmed.
|
||||
* The state of an erased block is undefined.
|
||||
* Negative error codes are propogated to the user.
|
||||
* May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
* @return errorcode. 0 on success.
|
||||
*/
|
||||
int littlefs_api_erase(const struct lfs_config *c, lfs_block_t block);
|
||||
|
||||
/**
|
||||
* @brief Sync the state of the underlying block device.
|
||||
*
|
||||
* Negative error codes are propogated to the user.
|
||||
*
|
||||
* @return errorcode. 0 on success.
|
||||
*/
|
||||
int littlefs_api_sync(const struct lfs_config *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -141,12 +141,11 @@ sample code bearing this copyright.
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "OneWire.h"
|
||||
#include "OneWire_direct_gpio.h"
|
||||
#include "util/OneWire_direct_gpio.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
|
||||
void OneWire::begin(uint8_t pin) {
|
||||
void OneWire::begin(uint8_t pin)
|
||||
{
|
||||
pinMode(pin, INPUT);
|
||||
bitmask = PIN_TO_BITMASK(pin);
|
||||
baseReg = PIN_TO_BASEREG(pin);
|
||||
@@ -155,19 +154,17 @@ void OneWire::begin(uint8_t pin) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Perform the onewire reset function. We will wait up to 250uS for
|
||||
// the bus to come high, if it doesn't then it is broken or shorted
|
||||
// and we return a 0;
|
||||
//
|
||||
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
|
||||
//
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t IRAM_ATTR OneWire::reset(void) {
|
||||
#else
|
||||
uint8_t OneWire::reset(void) {
|
||||
#endif
|
||||
uint8_t OneWire::reset(void)
|
||||
{
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE * reg IO_REG_BASE_ATTR = baseReg;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
|
||||
@@ -176,10 +173,9 @@ uint8_t OneWire::reset(void) {
|
||||
interrupts();
|
||||
// wait until the wire is high... just in case
|
||||
do {
|
||||
if (--retries == 0)
|
||||
return 0;
|
||||
if (--retries == 0) return 0;
|
||||
delayMicroseconds(2);
|
||||
} while (!DIRECT_READ(reg, mask));
|
||||
} while ( !DIRECT_READ(reg, mask));
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
@@ -199,13 +195,10 @@ uint8_t OneWire::reset(void) {
|
||||
// Write a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
void IRAM_ATTR OneWire::write_bit(uint8_t v) {
|
||||
#else
|
||||
void OneWire::write_bit(uint8_t v) {
|
||||
#endif
|
||||
void OneWire::write_bit(uint8_t v)
|
||||
{
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE * reg IO_REG_BASE_ATTR = baseReg;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
|
||||
if (v & 1) {
|
||||
noInterrupts();
|
||||
@@ -230,13 +223,10 @@ void OneWire::write_bit(uint8_t v) {
|
||||
// Read a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t IRAM_ATTR OneWire::read_bit(void) {
|
||||
#else
|
||||
uint8_t OneWire::read_bit(void) {
|
||||
#endif
|
||||
uint8_t OneWire::read_bit(void)
|
||||
{
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE * reg IO_REG_BASE_ATTR = baseReg;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
uint8_t r;
|
||||
|
||||
noInterrupts();
|
||||
@@ -262,9 +252,9 @@ void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
|
||||
uint8_t bitMask;
|
||||
|
||||
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
OneWire::write_bit((bitMask & v) ? 1 : 0);
|
||||
OneWire::write_bit( (bitMask & v)?1:0);
|
||||
}
|
||||
if (!power) {
|
||||
if ( !power) {
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
DIRECT_WRITE_LOW(baseReg, bitmask);
|
||||
@@ -272,8 +262,8 @@ void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
|
||||
}
|
||||
}
|
||||
|
||||
void OneWire::write_bytes(const uint8_t * buf, uint16_t count, bool power /* = 0 */) {
|
||||
for (uint16_t i = 0; i < count; i++)
|
||||
void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
|
||||
for (uint16_t i = 0 ; i < count ; i++)
|
||||
write(buf[i]);
|
||||
if (!power) {
|
||||
noInterrupts();
|
||||
@@ -291,37 +281,38 @@ uint8_t OneWire::read() {
|
||||
uint8_t r = 0;
|
||||
|
||||
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
if (OneWire::read_bit())
|
||||
r |= bitMask;
|
||||
if ( OneWire::read_bit()) r |= bitMask;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void OneWire::read_bytes(uint8_t * buf, uint16_t count) {
|
||||
for (uint16_t i = 0; i < count; i++)
|
||||
void OneWire::read_bytes(uint8_t *buf, uint16_t count) {
|
||||
for (uint16_t i = 0 ; i < count ; i++)
|
||||
buf[i] = read();
|
||||
}
|
||||
|
||||
//
|
||||
// Do a ROM select
|
||||
//
|
||||
void OneWire::select(const uint8_t rom[8]) {
|
||||
void OneWire::select(const uint8_t rom[8])
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
write(0x55); // Choose ROM
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
write(rom[i]);
|
||||
for (i = 0; i < 8; i++) write(rom[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Do a ROM skip
|
||||
//
|
||||
void OneWire::skip() {
|
||||
void OneWire::skip()
|
||||
{
|
||||
write(0xCC); // Skip ROM
|
||||
}
|
||||
|
||||
void OneWire::depower() {
|
||||
void OneWire::depower()
|
||||
{
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
interrupts();
|
||||
@@ -333,22 +324,23 @@ void OneWire::depower() {
|
||||
// You need to use this function to start a search again from the beginning.
|
||||
// You do not need to do it for the first search, though you could.
|
||||
//
|
||||
void OneWire::reset_search() {
|
||||
void OneWire::reset_search()
|
||||
{
|
||||
// reset the search state
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = false;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
for (int i = 7;; i--) {
|
||||
for(int i = 7; ; i--) {
|
||||
ROM_NO[i] = 0;
|
||||
if (i == 0)
|
||||
break;
|
||||
if ( i == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
//
|
||||
void OneWire::target_search(uint8_t family_code) {
|
||||
void OneWire::target_search(uint8_t family_code)
|
||||
{
|
||||
// set the search state to find SearchFamily type devices
|
||||
ROM_NO[0] = family_code;
|
||||
for (uint8_t i = 1; i < 8; i++)
|
||||
@@ -374,7 +366,8 @@ void OneWire::target_search(uint8_t family_code) {
|
||||
// Return TRUE : device found, ROM number in ROM_NO buffer
|
||||
// FALSE : device not found, end of search
|
||||
//
|
||||
bool OneWire::search(uint8_t * newAddr, bool search_mode /* = true */) {
|
||||
bool OneWire::search(uint8_t *newAddr, bool search_mode /* = true */)
|
||||
{
|
||||
uint8_t id_bit_number;
|
||||
uint8_t last_zero, rom_byte_number;
|
||||
bool search_result;
|
||||
@@ -408,7 +401,8 @@ bool OneWire::search(uint8_t * newAddr, bool search_mode /* = true */) {
|
||||
}
|
||||
|
||||
// loop to do the search
|
||||
do {
|
||||
do
|
||||
{
|
||||
// read a bit and its complement
|
||||
id_bit = read_bit();
|
||||
cmp_id_bit = read_bit();
|
||||
@@ -460,7 +454,8 @@ bool OneWire::search(uint8_t * newAddr, bool search_mode /* = true */) {
|
||||
rom_byte_mask = 1;
|
||||
}
|
||||
}
|
||||
} while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
|
||||
}
|
||||
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
|
||||
|
||||
// if the search was successful then
|
||||
if (!(id_bit_number < 65)) {
|
||||
@@ -482,12 +477,10 @@ bool OneWire::search(uint8_t * newAddr, bool search_mode /* = true */) {
|
||||
LastFamilyDiscrepancy = 0;
|
||||
search_result = false;
|
||||
} else {
|
||||
for (int i = 0; i < 8; i++)
|
||||
newAddr[i] = ROM_NO[i];
|
||||
for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
|
||||
}
|
||||
// depower(); // https://github.com/PaulStoffregen/OneWire/pull/80
|
||||
return search_result;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -500,17 +493,23 @@ bool OneWire::search(uint8_t * newAddr, bool search_mode /* = true */) {
|
||||
// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0
|
||||
// Tiny 2x16 entry CRC table created by Arjen Lentz
|
||||
// See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table
|
||||
static const uint8_t PROGMEM dscrc2x16_table[] = {0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83, 0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
|
||||
0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8, 0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74};
|
||||
static const uint8_t PROGMEM dscrc2x16_table[] = {
|
||||
0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
|
||||
0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
|
||||
0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8,
|
||||
0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74
|
||||
};
|
||||
|
||||
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
|
||||
// and the registers. (Use tiny 2x16 entry CRC table)
|
||||
uint8_t OneWire::crc8(const uint8_t * addr, uint8_t len) {
|
||||
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = *addr++ ^ crc; // just re-using crc as intermediate
|
||||
crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^ pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
|
||||
crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^
|
||||
pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
|
||||
}
|
||||
|
||||
return crc;
|
||||
@@ -520,7 +519,8 @@ uint8_t OneWire::crc8(const uint8_t * addr, uint8_t len) {
|
||||
// Compute a Dallas Semiconductor 8 bit CRC directly.
|
||||
// this is much slower, but a little smaller, than the lookup table.
|
||||
//
|
||||
uint8_t OneWire::crc8(const uint8_t * addr, uint8_t len) {
|
||||
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
@@ -531,8 +531,7 @@ uint8_t OneWire::crc8(const uint8_t * addr, uint8_t len) {
|
||||
for (uint8_t i = 8; i; i--) {
|
||||
uint8_t mix = (crc ^ inbyte) & 0x01;
|
||||
crc >>= 1;
|
||||
if (mix)
|
||||
crc ^= 0x8C;
|
||||
if (mix) crc ^= 0x8C;
|
||||
inbyte >>= 1;
|
||||
}
|
||||
#endif
|
||||
@@ -542,20 +541,23 @@ uint8_t OneWire::crc8(const uint8_t * addr, uint8_t len) {
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
bool OneWire::check_crc16(const uint8_t * input, uint16_t len, const uint8_t * inverted_crc, uint16_t crc) {
|
||||
bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)
|
||||
{
|
||||
crc = ~crc16(input, len, crc);
|
||||
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
|
||||
}
|
||||
|
||||
uint16_t OneWire::crc16(const uint8_t * input, uint16_t len, uint16_t crc) {
|
||||
uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc)
|
||||
{
|
||||
#if defined(__AVR__)
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
for (uint16_t i = 0 ; i < len ; i++) {
|
||||
crc = _crc16_update(crc, input[i]);
|
||||
}
|
||||
#else
|
||||
static const uint8_t oddparity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};
|
||||
static const uint8_t oddparity[16] =
|
||||
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
||||
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
for (uint16_t i = 0 ; i < len ; i++) {
|
||||
// Even though we're just copying a byte from the input,
|
||||
// we'll be doing 16-bit computation with it.
|
||||
uint16_t cdata = input[i];
|
||||
@@ -575,7 +577,4 @@ uint16_t OneWire::crc16(const uint8_t * input, uint16_t len, uint16_t crc) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -52,12 +52,13 @@
|
||||
#endif
|
||||
|
||||
// Board-specific macros for direct GPIO
|
||||
#include "OneWire_direct_regtype.h"
|
||||
#include "util/OneWire_direct_regtype.h"
|
||||
|
||||
class OneWire {
|
||||
class OneWire
|
||||
{
|
||||
private:
|
||||
IO_REG_TYPE bitmask;
|
||||
volatile IO_REG_TYPE * baseReg;
|
||||
volatile IO_REG_TYPE *baseReg;
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// global search state
|
||||
@@ -68,21 +69,14 @@ class OneWire {
|
||||
#endif
|
||||
|
||||
public:
|
||||
OneWire() {
|
||||
}
|
||||
OneWire(uint8_t pin) {
|
||||
begin(pin);
|
||||
}
|
||||
OneWire() { }
|
||||
OneWire(uint8_t pin) { begin(pin); }
|
||||
void begin(uint8_t pin);
|
||||
|
||||
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
|
||||
// with a presence pulse. Returns 0 if there is no device or the
|
||||
// bus is shorted or otherwise held low for more than 250uS
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t IRAM_ATTR reset(void);
|
||||
#else
|
||||
uint8_t reset(void);
|
||||
#endif
|
||||
|
||||
// Issue a 1-Wire rom select command, you do the reset first.
|
||||
void select(const uint8_t rom[8]);
|
||||
@@ -96,27 +90,20 @@ class OneWire {
|
||||
// another read or write.
|
||||
void write(uint8_t v, uint8_t power = 0);
|
||||
|
||||
void write_bytes(const uint8_t * buf, uint16_t count, bool power = 0);
|
||||
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);
|
||||
|
||||
// Read a byte.
|
||||
uint8_t read(void);
|
||||
|
||||
void read_bytes(uint8_t * buf, uint16_t count);
|
||||
void read_bytes(uint8_t *buf, uint16_t count);
|
||||
|
||||
// Write a bit. The bus is always left powered at the end, see
|
||||
// note in write() about that.
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
void IRAM_ATTR write_bit(uint8_t v);
|
||||
#else
|
||||
void write_bit(uint8_t v);
|
||||
#endif
|
||||
|
||||
// Read a bit.
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t IRAM_ATTR read_bit(void);
|
||||
#else
|
||||
uint8_t read_bit(void);
|
||||
#endif
|
||||
|
||||
// Stop forcing power onto the bus. You only need to do this if
|
||||
// you used the 'power' flag to write() or used a write_bit() call
|
||||
// and aren't about to do another read or write. You would rather
|
||||
@@ -138,13 +125,13 @@ class OneWire {
|
||||
// might be a good idea to check the CRC to make sure you didn't
|
||||
// get garbage. The order is deterministic. You will always get
|
||||
// the same devices in the same order.
|
||||
bool search(uint8_t * newAddr, bool search_mode = true);
|
||||
bool search(uint8_t *newAddr, bool search_mode = true);
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
|
||||
// ROM and scratchpad registers.
|
||||
static uint8_t crc8(const uint8_t * addr, uint8_t len);
|
||||
static uint8_t crc8(const uint8_t *addr, uint8_t len);
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
@@ -167,7 +154,7 @@ class OneWire {
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return True, iff the CRC matches.
|
||||
static bool check_crc16(const uint8_t * input, uint16_t len, const uint8_t * inverted_crc, uint16_t crc = 0);
|
||||
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0);
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
@@ -181,7 +168,7 @@ class OneWire {
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
static uint16_t crc16(const uint8_t * input, uint16_t len, uint16_t crc = 0);
|
||||
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1,409 +0,0 @@
|
||||
#ifndef OneWire_Direct_GPIO_h
|
||||
#define OneWire_Direct_GPIO_h
|
||||
|
||||
// This header should ONLY be included by OneWire.cpp. These defines are
|
||||
// meant to be private, used within OneWire.cpp, but not exposed to Arduino
|
||||
// sketches or other libraries which may include OneWire.h.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Platform specific I/O definitions
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR asm("r30")
|
||||
#define IO_REG_MASK_ATTR
|
||||
#if defined(__AVR_ATmega4809__)
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)-8)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)-8)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)-4)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)-4)) |= (mask))
|
||||
#else
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base) + 1)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base) + 1)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base) + 2)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base) + 2)) |= (mask))
|
||||
#endif
|
||||
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (1)
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR __attribute__((unused))
|
||||
#define DIRECT_READ(base, mask) (*((base) + 512))
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base) + 640) = 0)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base) + 640) = 1)
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base) + 256) = 1)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base) + 128) = 1)
|
||||
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((*((base) + 16) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base) + 20) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base) + 20) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base) + 8) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base) + 4) = (mask))
|
||||
|
||||
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((*((base) + 2) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base) + 1) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base) + 1) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base) + 34) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base) + 33) = (mask))
|
||||
|
||||
#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__)
|
||||
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
|
||||
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
|
||||
// If you have trouble with OneWire on Arduino Due, please check the
|
||||
// status of delayMicroseconds() before reporting a bug in OneWire!
|
||||
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*((base) + 15)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base) + 5)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base) + 4)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base) + 13)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base) + 12)) = (mask))
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||
#endif
|
||||
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*(base + 4)) & (mask)) ? 1 : 0) //PORTX + 0x10
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*(base + 2)) = (mask)) //TRISXSET + 0x08
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base + 1)) = (mask)) //TRISXCLR + 0x04
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*(base + 8 + 1)) = (mask)) //LATXCLR + 0x24
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*(base + 8 + 2)) = (mask)) //LATXSET + 0x28
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
// Special note: I depend on the ESP community to maintain these definitions and
|
||||
// submit good pull requests. I can not answer any ESP questions or help you
|
||||
// resolve any problems related to ESP chips. Please do not contact me and please
|
||||
// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked
|
||||
// on ESP community forums.
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)GPO)
|
||||
#define PIN_TO_BITMASK(pin) (1 << pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS
|
||||
#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS
|
||||
#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#include <driver/rtc_io.h>
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline)) IO_REG_TYPE directRead(IO_REG_TYPE pin) {
|
||||
if (pin < 32)
|
||||
return (GPIO.in >> pin) & 0x1;
|
||||
else if (pin < 40)
|
||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directWriteLow(IO_REG_TYPE pin) {
|
||||
if (pin < 32)
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
else if (pin < 34)
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directWriteHigh(IO_REG_TYPE pin) {
|
||||
if (pin < 32)
|
||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||
else if (pin < 34)
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directModeInput(IO_REG_TYPE pin) {
|
||||
if (digitalPinIsValid(pin)) {
|
||||
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
||||
|
||||
if (rtc_reg) // RTC pins PULL settings
|
||||
{
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
|
||||
if (pin < 32)
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
|
||||
uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
||||
pinFunction |= FUN_IE; // input enable but required for output as well?
|
||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
||||
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
|
||||
GPIO.pin[pin].val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directModeOutput(IO_REG_TYPE pin) {
|
||||
if (digitalPinIsValid(pin) && pin <= 33) // pins above 33 can be only inputs
|
||||
{
|
||||
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
||||
|
||||
if (rtc_reg) // RTC pins PULL settings
|
||||
{
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
|
||||
if (pin < 32)
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
else // already validated to pins <= 33
|
||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
|
||||
uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
||||
pinFunction |= FUN_IE; // input enable but required for output as well?
|
||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
||||
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
|
||||
GPIO.pin[pin].val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin)
|
||||
// https://github.com/PaulStoffregen/OneWire/pull/47
|
||||
// https://github.com/stickbreaker/OneWire/commit/6eb7fc1c11a15b6ac8c60e5671cf36eb6829f82c
|
||||
#ifdef interrupts
|
||||
#undef interrupts
|
||||
#endif
|
||||
#ifdef noInterrupts
|
||||
#undef noInterrupts
|
||||
#endif
|
||||
#define noInterrupts() \
|
||||
{ \
|
||||
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; \
|
||||
portENTER_CRITICAL(&mux)
|
||||
#define interrupts() \
|
||||
portEXIT_CRITICAL(&mux); \
|
||||
}
|
||||
//#warning "ESP32 OneWire testing"
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) ((uint32_t)digitalPinToPinName(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) digitalReadFast((PinName)pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) digitalWriteFast((PinName)pin, LOW)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) digitalWriteFast((PinName)pin, HIGH)
|
||||
#define DIRECT_MODE_INPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0))
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0))
|
||||
|
||||
#elif defined(__SAMD21G18A__)
|
||||
#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*((base) + 8)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base) + 1)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base) + 2)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base) + 5)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base) + 6)) = (mask))
|
||||
|
||||
#elif defined(__ASR6501__)
|
||||
#define PIN_IN_PORT(pin) (pin % PIN_NUMBER_IN_PORT)
|
||||
#define PORT_FROM_PIN(pin) (pin / PIN_NUMBER_IN_PORT)
|
||||
#define PORT_OFFSET(port) (PORT_REG_SHFIT * port)
|
||||
#define PORT_ADDRESS(pin) (CYDEV_GPIO_BASE + PORT_OFFSET(PORT_FROM_PIN(pin)))
|
||||
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) CY_SYS_PINS_READ_PIN(PORT_ADDRESS(pin) + 4, PIN_IN_PORT(pin))
|
||||
#define DIRECT_WRITE_LOW(base, pin) CY_SYS_PINS_CLEAR_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin))
|
||||
#define DIRECT_WRITE_HIGH(base, pin) CY_SYS_PINS_SET_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin))
|
||||
#define DIRECT_MODE_INPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin) + 8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_DIG_HIZ)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin) + 8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_STRONG)
|
||||
|
||||
#elif defined(RBL_NRF51822)
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin)
|
||||
|
||||
#elif defined(__arc__) /* Arduino101/Genuino101 specifics */
|
||||
|
||||
#include "scss_registers.h"
|
||||
#include "portable.h"
|
||||
#include "avr/pgmspace.h"
|
||||
|
||||
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
|
||||
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
|
||||
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
|
||||
#define DIR_OFFSET_SS 0x01
|
||||
#define DIR_OFFSET_SOC 0x04
|
||||
#define EXT_PORT_OFFSET_SS 0x0A
|
||||
#define EXT_PORT_OFFSET_SOC 0x50
|
||||
|
||||
/* GPIO registers base address */
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
|
||||
#define PIN_TO_BITMASK(pin) pin
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline)) IO_REG_TYPE directRead(volatile IO_REG_TYPE * base, IO_REG_TYPE pin) {
|
||||
IO_REG_TYPE ret;
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
|
||||
} else {
|
||||
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
|
||||
}
|
||||
return ((ret >> GPIO_ID(pin)) & 0x01);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directModeInput(volatile IO_REG_TYPE * base, IO_REG_TYPE pin) {
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)), ((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directModeOutput(volatile IO_REG_TYPE * base, IO_REG_TYPE pin) {
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)), ((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directWriteLow(volatile IO_REG_TYPE * base, IO_REG_TYPE pin) {
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directWriteHigh(volatile IO_REG_TYPE * base, IO_REG_TYPE pin) {
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(base, pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
/*
|
||||
* Tested on highfive1
|
||||
*
|
||||
* Stable results are achieved operating in the
|
||||
* two high speed modes of the highfive1. It
|
||||
* seems to be less reliable in slow mode.
|
||||
*/
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) digitalPinToBitMask(pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline)) IO_REG_TYPE directRead(IO_REG_TYPE mask) {
|
||||
return ((GPIO_REG(GPIO_INPUT_VAL) & mask) != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directModeInput(IO_REG_TYPE mask) {
|
||||
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
|
||||
GPIO_REG(GPIO_IOF_EN) &= ~mask;
|
||||
|
||||
GPIO_REG(GPIO_INPUT_EN) |= mask;
|
||||
GPIO_REG(GPIO_OUTPUT_EN) &= ~mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directModeOutput(IO_REG_TYPE mask) {
|
||||
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
|
||||
GPIO_REG(GPIO_IOF_EN) &= ~mask;
|
||||
|
||||
GPIO_REG(GPIO_INPUT_EN) &= ~mask;
|
||||
GPIO_REG(GPIO_OUTPUT_EN) |= mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directWriteLow(IO_REG_TYPE mask) {
|
||||
GPIO_REG(GPIO_OUTPUT_VAL) &= ~mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void directWriteHigh(IO_REG_TYPE mask) {
|
||||
GPIO_REG(GPIO_OUTPUT_VAL) |= mask;
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, mask) directRead(mask)
|
||||
#define DIRECT_WRITE_LOW(base, mask) directWriteLow(mask)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) directWriteHigh(mask)
|
||||
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
|
||||
|
||||
#else
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE unsigned int
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) digitalRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH)
|
||||
#define DIRECT_MODE_INPUT(base, pin) pinMode(pin, INPUT)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin, OUTPUT)
|
||||
#warning "OneWire. Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite. Operation of this library is not guaranteed on this architecture."
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
445
lib/OneWire/util/OneWire_direct_gpio.h
Normal file
445
lib/OneWire/util/OneWire_direct_gpio.h
Normal file
@@ -0,0 +1,445 @@
|
||||
#ifndef OneWire_Direct_GPIO_h
|
||||
#define OneWire_Direct_GPIO_h
|
||||
|
||||
// This header should ONLY be included by OneWire.cpp. These defines are
|
||||
// meant to be private, used within OneWire.cpp, but not exposed to Arduino
|
||||
// sketches or other libraries which may include OneWire.h.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Platform specific I/O definitions
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR asm("r30")
|
||||
#define IO_REG_MASK_ATTR
|
||||
#if defined(__AVR_ATmega4809__)
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)-8)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)-8)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)-4)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)-4)) |= (mask))
|
||||
#else
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
|
||||
#endif
|
||||
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (1)
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR __attribute__ ((unused))
|
||||
#define DIRECT_READ(base, mask) (*((base)+512))
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
|
||||
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask))
|
||||
|
||||
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((*((base)+2) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+1) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+1) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+34) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+33) = (mask))
|
||||
|
||||
#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__)
|
||||
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
|
||||
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
|
||||
// If you have trouble with OneWire on Arduino Due, please check the
|
||||
// status of delayMicroseconds() before reporting a bug in OneWire!
|
||||
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||
#endif
|
||||
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
// Special note: I depend on the ESP community to maintain these definitions and
|
||||
// submit good pull requests. I can not answer any ESP questions or help you
|
||||
// resolve any problems related to ESP chips. Please do not contact me and please
|
||||
// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked
|
||||
// on ESP community forums.
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO)
|
||||
#define PIN_TO_BITMASK(pin) (1 << pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS
|
||||
#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS
|
||||
#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#include <driver/rtc_io.h>
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(IO_REG_TYPE pin)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return (GPIO.in.val >> pin) & 0x1;
|
||||
#else // plain ESP32
|
||||
if ( pin < 32 )
|
||||
return (GPIO.in >> pin) & 0x1;
|
||||
else if ( pin < 46 )
|
||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(IO_REG_TYPE pin)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
GPIO.out_w1tc.val = ((uint32_t)1 << pin);
|
||||
#else // plain ESP32
|
||||
if ( pin < 32 )
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
else if ( pin < 46 )
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(IO_REG_TYPE pin)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
GPIO.out_w1ts.val = ((uint32_t)1 << pin);
|
||||
#else // plain ESP32
|
||||
if ( pin < 32 )
|
||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||
else if ( pin < 46 )
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(IO_REG_TYPE pin)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
|
||||
#else
|
||||
if ( digitalPinIsValid(pin) )
|
||||
{
|
||||
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
|
||||
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
||||
|
||||
if ( rtc_reg ) // RTC pins PULL settings
|
||||
{
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
#endif
|
||||
// Input
|
||||
if ( pin < 32 )
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(IO_REG_TYPE pin)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
|
||||
#else
|
||||
if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs
|
||||
{
|
||||
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
|
||||
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
||||
|
||||
if ( rtc_reg ) // RTC pins PULL settings
|
||||
{
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
#endif
|
||||
// Output
|
||||
if ( pin < 32 )
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
else // already validated to pins <= 33
|
||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin)
|
||||
// https://github.com/PaulStoffregen/OneWire/pull/47
|
||||
// https://github.com/stickbreaker/OneWire/commit/6eb7fc1c11a15b6ac8c60e5671cf36eb6829f82c
|
||||
#ifdef interrupts
|
||||
#undef interrupts
|
||||
#endif
|
||||
#ifdef noInterrupts
|
||||
#undef noInterrupts
|
||||
#endif
|
||||
#define noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
|
||||
#define interrupts() portEXIT_CRITICAL(&mux);}
|
||||
//#warning "ESP32 OneWire testing"
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) ((uint32_t)digitalPinToPinName(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) digitalReadFast((PinName)pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) digitalWriteFast((PinName)pin, LOW)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) digitalWriteFast((PinName)pin, HIGH)
|
||||
#define DIRECT_MODE_INPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0))
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0))
|
||||
|
||||
#elif defined(__SAMD21G18A__)
|
||||
#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask))
|
||||
|
||||
#elif defined(__ASR6501__)
|
||||
#define PIN_IN_PORT(pin) (pin % PIN_NUMBER_IN_PORT)
|
||||
#define PORT_FROM_PIN(pin) (pin / PIN_NUMBER_IN_PORT)
|
||||
#define PORT_OFFSET(port) (PORT_REG_SHFIT * port)
|
||||
#define PORT_ADDRESS(pin) (CYDEV_GPIO_BASE + PORT_OFFSET(PORT_FROM_PIN(pin)))
|
||||
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) CY_SYS_PINS_READ_PIN(PORT_ADDRESS(pin)+4, PIN_IN_PORT(pin))
|
||||
#define DIRECT_WRITE_LOW(base, pin) CY_SYS_PINS_CLEAR_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin))
|
||||
#define DIRECT_WRITE_HIGH(base, pin) CY_SYS_PINS_SET_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin))
|
||||
#define DIRECT_MODE_INPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin)+8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_DIG_HIZ)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin)+8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_STRONG)
|
||||
|
||||
#elif defined(RBL_NRF51822)
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin)
|
||||
|
||||
#elif defined(__arc__) /* Arduino101/Genuino101 specifics */
|
||||
|
||||
#include "scss_registers.h"
|
||||
#include "portable.h"
|
||||
#include "avr/pgmspace.h"
|
||||
|
||||
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
|
||||
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
|
||||
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
|
||||
#define DIR_OFFSET_SS 0x01
|
||||
#define DIR_OFFSET_SOC 0x04
|
||||
#define EXT_PORT_OFFSET_SS 0x0A
|
||||
#define EXT_PORT_OFFSET_SOC 0x50
|
||||
|
||||
/* GPIO registers base address */
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
|
||||
#define PIN_TO_BITMASK(pin) pin
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
IO_REG_TYPE ret;
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
|
||||
} else {
|
||||
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
|
||||
}
|
||||
return ((ret >> GPIO_ID(pin)) & 0x01);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)),
|
||||
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)),
|
||||
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(base, pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
/*
|
||||
* Tested on highfive1
|
||||
*
|
||||
* Stable results are achieved operating in the
|
||||
* two high speed modes of the highfive1. It
|
||||
* seems to be less reliable in slow mode.
|
||||
*/
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) digitalPinToBitMask(pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(IO_REG_TYPE mask)
|
||||
{
|
||||
return ((GPIO_REG(GPIO_INPUT_VAL) & mask) != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
|
||||
GPIO_REG(GPIO_IOF_EN) &= ~mask;
|
||||
|
||||
GPIO_REG(GPIO_INPUT_EN) |= mask;
|
||||
GPIO_REG(GPIO_OUTPUT_EN) &= ~mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
|
||||
GPIO_REG(GPIO_IOF_EN) &= ~mask;
|
||||
|
||||
GPIO_REG(GPIO_INPUT_EN) &= ~mask;
|
||||
GPIO_REG(GPIO_OUTPUT_EN) |= mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_VAL) &= ~mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_VAL) |= mask;
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, mask) directRead(mask)
|
||||
#define DIRECT_WRITE_LOW(base, mask) directWriteLow(mask)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) directWriteHigh(mask)
|
||||
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
|
||||
|
||||
#else
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE unsigned int
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) digitalRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH)
|
||||
#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT)
|
||||
#warning "OneWire. Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite. Operation of this library is not guaranteed on this architecture."
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -47,7 +47,7 @@ void APSettingsService::manageAP() {
|
||||
|
||||
void APSettingsService::startAP() {
|
||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||
esp_wifi_set_bandwidth(ESP_IF_WIFI_AP, WIFI_BW_HT20);
|
||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
|
||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
||||
if (!_dnsServer) {
|
||||
IPAddress apIp = WiFi.softAPIP();
|
||||
|
||||
@@ -19,7 +19,7 @@ void FactoryResetService::handleRequest(AsyncWebServerRequest * request) {
|
||||
*/
|
||||
void FactoryResetService::factoryReset() {
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
File root = fs->open(FS_CONFIG_DIRECTORY);
|
||||
|
||||
@@ -99,23 +99,17 @@ void MqttSettingsService::onConfigUpdated() {
|
||||
|
||||
void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
emsesp::EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||
if (!networkSettings.enableIPv6 && _state.enabled) {
|
||||
// emsesp::EMSESP::logger().info(F("IPv4 Network connection found, starting MQTT client"));
|
||||
onConfigUpdated();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case SYSTEM_EVENT_GOT_IP6:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
if (_state.enabled) {
|
||||
// emsesp::EMSESP::logger().info(F("IPv6 Network connection found, starting MQTT client"));
|
||||
// emsesp::EMSESP::logger().info(F("Network connection found, starting MQTT client"));
|
||||
onConfigUpdated();
|
||||
}
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
if (_state.enabled) {
|
||||
// emsesp::EMSESP::logger().info(F("Network connection dropped, stopping MQTT client"));
|
||||
_mqttClient.disconnect();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <NTPSettingsService.h>
|
||||
#include <esp_sntp.h>
|
||||
|
||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||
|
||||
@@ -25,15 +26,15 @@ void NTPSettingsService::begin() {
|
||||
// handles both WiFI and Ethernet
|
||||
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
emsesp::EMSESP::logger().info(F("WiFi connection dropped, stopping NTP"));
|
||||
connected_ = false;
|
||||
configureNTP();
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
// emsesp::EMSESP::logger().info(F("Got IP address, starting NTP synchronization"));
|
||||
connected_ = true;
|
||||
configureNTP();
|
||||
|
||||
@@ -57,8 +57,6 @@ void NetworkSettingsService::manageSTA() {
|
||||
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
||||
if (_state.staticIPConfig) {
|
||||
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
|
||||
} else {
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // configure for DHCP
|
||||
}
|
||||
|
||||
WiFi.setHostname(_state.hostname.c_str()); // set hostname
|
||||
@@ -66,9 +64,9 @@ void NetworkSettingsService::manageSTA() {
|
||||
// www.esp32.com/viewtopic.php?t=12055
|
||||
read([&](NetworkSettings & networkSettings) {
|
||||
if (networkSettings.bandwidth20) {
|
||||
esp_wifi_set_bandwidth(ESP_IF_WIFI_STA, WIFI_BW_HT20);
|
||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_STA, WIFI_BW_HT20);
|
||||
} else {
|
||||
esp_wifi_set_bandwidth(ESP_IF_WIFI_STA, WIFI_BW_HT40);
|
||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_STA, WIFI_BW_HT40);
|
||||
}
|
||||
esp_wifi_set_max_tx_power(networkSettings.tx_power * 4);
|
||||
if (networkSettings.nosleep) {
|
||||
@@ -82,7 +80,7 @@ void NetworkSettingsService::manageSTA() {
|
||||
|
||||
// handles if wifi stopped
|
||||
void NetworkSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
if (event == SYSTEM_EVENT_STA_STOP) {
|
||||
if (event == ARDUINO_EVENT_WIFI_STA_STOP) {
|
||||
if (_stopping) {
|
||||
_lastConnectionAttempt = 0;
|
||||
_stopping = false;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#define NETWORK_SETTINGS_FILE "/config/networkSettings.json"
|
||||
#define NETWORK_SETTINGS_SERVICE_PATH "/rest/networkSettings"
|
||||
#define WIFI_RECONNECTION_DELAY 1000 * 30
|
||||
#define WIFI_RECONNECTION_DELAY 1000 * 3
|
||||
|
||||
#ifndef FACTORY_WIFI_SSID
|
||||
#define FACTORY_WIFI_SSID ""
|
||||
|
||||
@@ -66,8 +66,8 @@ void OTASettingsService::configureArduinoOTA() {
|
||||
|
||||
void OTASettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
configureArduinoOTA();
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef FS_BUFFER_SIZE
|
||||
#define FS_BUFFER_SIZE 4096
|
||||
#define FS_BUFFER_SIZE 8192
|
||||
#endif
|
||||
|
||||
enum class StateUpdateResult {
|
||||
|
||||
@@ -24,8 +24,8 @@ void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
||||
root["flash_chip_size"] = ESP.getFlashChipSize();
|
||||
root["flash_chip_speed"] = ESP.getFlashChipSpeed();
|
||||
|
||||
root["fs_total"] = LITTLEFS.totalBytes();
|
||||
root["fs_used"] = LITTLEFS.usedBytes();
|
||||
root["fs_total"] = LittleFS.totalBytes();
|
||||
root["fs_used"] = LittleFS.usedBytes();
|
||||
root["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
|
||||
|
||||
response->setLength();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <FS.h>
|
||||
#include <LITTLEFS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
@@ -28,8 +28,10 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
std::string extension = fname.substr(position + 1);
|
||||
size_t fsize = request->contentLength();
|
||||
|
||||
#if defined(EMSESP_USE_SERIAL)
|
||||
Serial.printf("Received filename: %s, len: %d, index: %d, ext: %s, fsize: %d", filename.c_str(), len, index, extension.c_str(), fsize);
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if ((extension == "bin") && (fsize > 1500000)) {
|
||||
is_firmware = true;
|
||||
@@ -52,7 +54,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
}
|
||||
} else {
|
||||
// its a normal file, open a new temp file to write the contents too
|
||||
request->_tempFile = LITTLEFS.open(TEMP_FILENAME_PATH, "w");
|
||||
request->_tempFile = LittleFS.open(TEMP_FILENAME_PATH, "w");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <Update.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <LITTLEFS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
@@ -117,6 +117,7 @@ void SyslogService::remove_queued_messages(uuid::log::Level level) {
|
||||
}
|
||||
|
||||
log_message_id_ -= offset;
|
||||
log_message_fails_ += offset;
|
||||
}
|
||||
|
||||
void SyslogService::log_level(uuid::log::Level level) {
|
||||
@@ -232,6 +233,7 @@ void SyslogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
|
||||
if (log_messages_.size() >= maximum_log_messages_) {
|
||||
log_messages_overflow_ = true;
|
||||
log_messages_.pop_front();
|
||||
log_message_fails_++;
|
||||
}
|
||||
|
||||
log_messages_.emplace_back(log_message_id_++, std::move(message));
|
||||
|
||||
@@ -198,6 +198,13 @@ class SyslogService : public uuid::log::Handler {
|
||||
return ip_;
|
||||
}
|
||||
|
||||
unsigned long message_count() {
|
||||
return log_message_id_;
|
||||
}
|
||||
unsigned long message_fails() {
|
||||
return log_message_fails_;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Log message that has been queued.
|
||||
@@ -270,6 +277,7 @@ class SyslogService : public uuid::log::Handler {
|
||||
std::atomic<bool> log_messages_overflow_{false}; /*!< Check if log messages have overflowed the buffer. @since 1.0.0 */
|
||||
uint64_t mark_interval_ = 0; /*!< Mark interval in milliseconds. @since 2.0.0 */
|
||||
uint64_t last_message_ = 0; /*!< Last message/mark time. @since 2.0.0 */
|
||||
unsigned long log_message_fails_ = 0;
|
||||
};
|
||||
|
||||
} // namespace syslog
|
||||
|
||||
@@ -33,7 +33,6 @@ class DummySettings {
|
||||
uint32_t syslog_mark_interval = 0;
|
||||
String syslog_host = "192.168.1.4";
|
||||
uint16_t syslog_port = 514;
|
||||
uint8_t master_thermostat = 0;
|
||||
bool shower_timer = true;
|
||||
bool shower_alert = false;
|
||||
uint8_t shower_alert_coldshot = 10;
|
||||
|
||||
@@ -20,34 +20,35 @@ typedef enum {
|
||||
typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_MAX } eth_phy_type_t;
|
||||
|
||||
typedef enum {
|
||||
SYSTEM_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */
|
||||
SYSTEM_EVENT_SCAN_DONE, /**< ESP32 finish scanning AP */
|
||||
SYSTEM_EVENT_STA_START, /**< ESP32 station start */
|
||||
SYSTEM_EVENT_STA_STOP, /**< ESP32 station stop */
|
||||
SYSTEM_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
||||
SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
|
||||
SYSTEM_EVENT_STA_GOT_IP, /**< ESP32 station got IP from connected AP */
|
||||
SYSTEM_EVENT_STA_LOST_IP, /**< ESP32 station lost IP and the IP is reset to 0 */
|
||||
SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP, /*!< ESP32 station wps overlap in enrollee mode */
|
||||
SYSTEM_EVENT_AP_START, /**< ESP32 soft-AP start */
|
||||
SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
|
||||
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_STAIPASSIGNED, /**< ESP32 soft-AP assign an IP to a connected station */
|
||||
SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
|
||||
SYSTEM_EVENT_GOT_IP6, /**< ESP32 station or ap or ethernet interface v6IP addr is preferred */
|
||||
SYSTEM_EVENT_ETH_START, /**< ESP32 ethernet start */
|
||||
SYSTEM_EVENT_ETH_STOP, /**< ESP32 ethernet stop */
|
||||
SYSTEM_EVENT_ETH_CONNECTED, /**< ESP32 ethernet phy link up */
|
||||
SYSTEM_EVENT_ETH_DISCONNECTED, /**< ESP32 ethernet phy link down */
|
||||
SYSTEM_EVENT_ETH_GOT_IP, /**< ESP32 ethernet got IP from connected AP */
|
||||
SYSTEM_EVENT_MAX
|
||||
} system_event_id_t;
|
||||
ARDUINO_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */
|
||||
ARDUINO_EVENT_SCAN_DONE, /**< ESP32 finish scanning AP */
|
||||
ARDUINO_EVENT_WIFI_STA_START, /**< ESP32 station start */
|
||||
ARDUINO_EVENT_WIFI_STA_STOP, /**< ESP32 station stop */
|
||||
ARDUINO_EVENT_WIFI_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
ARDUINO_EVENT_WIFI_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
||||
ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
|
||||
ARDUINO_EVENT_WIFI_STA_GOT_IP, /**< ESP32 station got IP from connected AP */
|
||||
ARDUINO_EVENT_WIFI_STA_LOST_IP, /**< ESP32 station lost IP and the IP is reset to 0 */
|
||||
ARDUINO_EVENT_WIFI_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
|
||||
ARDUINO_EVENT_WIFI_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
|
||||
ARDUINO_EVENT_WIFI_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
|
||||
ARDUINO_EVENT_WIFI_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
|
||||
ARDUINO_EVENT_WIFI_STA_WPS_ER_PBC_OVERLAP, /*!< ESP32 station wps overlap in enrollee mode */
|
||||
ARDUINO_EVENT_WIFI_AP_START, /**< ESP32 soft-AP start */
|
||||
ARDUINO_EVENT_WIFI_AP_STOP, /**< ESP32 soft-AP stop */
|
||||
ARDUINO_EVENT_WIFI_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||
ARDUINO_EVENT_WIFI_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
|
||||
ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED, /**< ESP32 soft-AP assign an IP to a connected station */
|
||||
ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
|
||||
ARDUINO_EVENT_WIFI_STA_GOT_IP6, /**< ESP32 station or ap or ethernet interface v6IP addr is preferred */
|
||||
ARDUINO_EVENT_ETH_GOT_IP6, /**< ESP32 station or ap or ethernet interface v6IP addr is preferred */
|
||||
ARDUINO_EVENT_ETH_START, /**< ESP32 ethernet start */
|
||||
ARDUINO_EVENT_ETH_STOP, /**< ESP32 ethernet stop */
|
||||
ARDUINO_EVENT_ETH_CONNECTED, /**< ESP32 ethernet phy link up */
|
||||
ARDUINO_EVENT_ETH_DISCONNECTED, /**< ESP32 ethernet phy link down */
|
||||
ARDUINO_EVENT_ETH_GOT_IP, /**< ESP32 ethernet got IP from connected AP */
|
||||
ARDUINO_EVENT_MAX
|
||||
} arduino_event_id_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */
|
||||
@@ -60,74 +61,60 @@ typedef enum {
|
||||
} wifi_auth_mode_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t status; /**< status of scanning APs */
|
||||
uint8_t number;
|
||||
uint8_t scan_id;
|
||||
} system_event_sta_scan_done_t;
|
||||
uint32_t status; /**< status of scanning APs: 0 — success, 1 - failure */
|
||||
uint8_t number; /**< number of scan results */
|
||||
uint8_t scan_id; /**< scan sequence number, used for block scan */
|
||||
} wifi_event_sta_scan_done_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_CONNECTED event */
|
||||
typedef struct {
|
||||
uint8_t ssid[32]; /**< SSID of connected AP */
|
||||
uint8_t ssid_len; /**< SSID length of connected AP */
|
||||
uint8_t bssid[6]; /**< BSSID of connected AP*/
|
||||
uint8_t channel; /**< channel of connected AP*/
|
||||
wifi_auth_mode_t authmode;
|
||||
} system_event_sta_connected_t;
|
||||
wifi_auth_mode_t authmode;/**< authentication mode used by AP*/
|
||||
} wifi_event_sta_connected_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_DISCONNECTED event */
|
||||
typedef struct {
|
||||
uint8_t ssid[32]; /**< SSID of disconnected AP */
|
||||
uint8_t ssid_len; /**< SSID length of disconnected AP */
|
||||
uint8_t bssid[6]; /**< BSSID of disconnected AP */
|
||||
uint8_t reason; /**< reason of disconnection */
|
||||
} system_event_sta_disconnected_t;
|
||||
} wifi_event_sta_disconnected_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_AUTHMODE_CHANGE event */
|
||||
typedef struct {
|
||||
wifi_auth_mode_t old_mode; /**< the old auth mode of AP */
|
||||
wifi_auth_mode_t new_mode; /**< the new auth mode of AP */
|
||||
} system_event_sta_authmode_change_t;
|
||||
} wifi_event_sta_authmode_change_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_WPS_ER_PIN event */
|
||||
typedef struct {
|
||||
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
|
||||
} system_event_sta_wps_er_pin_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
|
||||
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
|
||||
} system_event_ap_staconnected_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station disconnects to ESP32 soft-AP */
|
||||
uint8_t aid; /**< the aid that ESP32 soft-AP gave to the station disconnects to */
|
||||
} system_event_ap_stadisconnected_t;
|
||||
|
||||
typedef struct {
|
||||
int rssi; /**< Received probe request signal strength */
|
||||
uint8_t mac[6]; /**< MAC address of the station which send probe request */
|
||||
} system_event_ap_probe_req_rx_t;
|
||||
} wifi_event_sta_wps_er_pin_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_WPS_ER_FAILED event */
|
||||
typedef enum {
|
||||
WPS_FAIL_REASON_NORMAL = 0, /**< ESP32 WPS normal fail reason */
|
||||
WPS_FAIL_REASON_RECV_M2D, /**< ESP32 WPS receive M2D frame */
|
||||
WPS_FAIL_REASON_MAX
|
||||
} system_event_sta_wps_fail_reason_t;
|
||||
} wifi_event_sta_wps_fail_reason_t;
|
||||
|
||||
typedef union {
|
||||
system_event_sta_connected_t connected; /**< ESP32 station connected to AP */
|
||||
system_event_sta_disconnected_t disconnected; /**< ESP32 station disconnected to AP */
|
||||
system_event_sta_scan_done_t scan_done; /**< ESP32 station scan (APs) done */
|
||||
system_event_sta_authmode_change_t auth_change; /**< the auth mode of AP ESP32 station connected to changed */
|
||||
system_event_sta_wps_fail_reason_t sta_er_fail_reason; /**< ESP32 station WPS enrollee mode failed reason code received */
|
||||
system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */
|
||||
system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */
|
||||
system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */
|
||||
} system_event_info_t;
|
||||
wifi_event_sta_scan_done_t wifi_scan_done;
|
||||
wifi_event_sta_authmode_change_t wifi_sta_authmode_change;
|
||||
wifi_event_sta_connected_t wifi_sta_connected;
|
||||
wifi_event_sta_disconnected_t wifi_sta_disconnected;
|
||||
} arduino_event_info_t;
|
||||
|
||||
typedef struct {
|
||||
system_event_id_t event_id; /**< event ID */
|
||||
system_event_info_t event_info; /**< event information */
|
||||
} system_event_t;
|
||||
arduino_event_id_t event_id; /**< event ID */
|
||||
arduino_event_info_t event_info; /**< event information */
|
||||
} arduino_event_t;
|
||||
|
||||
#define WiFiEvent_t system_event_id_t
|
||||
#define WiFiEventInfo_t system_event_info_t
|
||||
#define WiFiEvent_t arduino_event_id_t
|
||||
#define WiFiEventInfo_t arduino_event_info_t
|
||||
#define WiFiEventId_t wifi_event_id_t
|
||||
|
||||
typedef enum {
|
||||
@@ -141,20 +128,20 @@ typedef enum {
|
||||
WL_DISCONNECTED = 6
|
||||
} wl_status_t;
|
||||
|
||||
typedef void (*WiFiEventCb)(system_event_id_t event);
|
||||
typedef std::function<void(system_event_id_t event, system_event_info_t info)> WiFiEventFuncCb;
|
||||
typedef void (*WiFiEventSysCb)(system_event_t * event);
|
||||
typedef void (*WiFiEventCb)(arduino_event_id_t event);
|
||||
typedef std::function<void(arduino_event_id_t event, arduino_event_info_t info)> WiFiEventFuncCb;
|
||||
typedef void (*WiFiEventSysCb)(arduino_event_t * event);
|
||||
typedef size_t wifi_event_id_t;
|
||||
|
||||
class WiFiClass {
|
||||
public:
|
||||
wifi_event_id_t onEvent(WiFiEventCb cbEvent, system_event_id_t event = SYSTEM_EVENT_MAX) {
|
||||
wifi_event_id_t onEvent(WiFiEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX) {
|
||||
return 0;
|
||||
};
|
||||
wifi_event_id_t onEvent(WiFiEventFuncCb cbEvent, system_event_id_t event = SYSTEM_EVENT_MAX) {
|
||||
wifi_event_id_t onEvent(WiFiEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX) {
|
||||
return 0;
|
||||
};
|
||||
wifi_event_id_t onEvent(WiFiEventSysCb cbEvent, system_event_id_t event = SYSTEM_EVENT_MAX) {
|
||||
wifi_event_id_t onEvent(WiFiEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef FS_BUFFER_SIZE
|
||||
#define FS_BUFFER_SIZE 4096
|
||||
#define FS_BUFFER_SIZE 8192
|
||||
#endif
|
||||
|
||||
enum class StateUpdateResult {
|
||||
|
||||
@@ -1,40 +1,5 @@
|
||||
(<https://github.com/emsesp/EMS-ESP32/issues/41>)
|
||||
(Based on <https://github.com/emsesp/EMS-ESP32/issues/41>)
|
||||
|
||||
When developing and testing the web interface, it's handy not to bother with re-flashing an ESP32 each time. The idea is to mimic the ESP using a mock/stub server that responds to the REST (HTTP POST & GET) and WebSocket calls.
|
||||
|
||||
To set it up it do
|
||||
|
||||
```sh
|
||||
% cd mock-api
|
||||
% npm install
|
||||
% cd interface
|
||||
% npm install
|
||||
```
|
||||
|
||||
and to run it
|
||||
|
||||
```sh
|
||||
% cd interface
|
||||
% npm run standalone
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- new file `interface/src/setupProxy.js`
|
||||
- new files `mock-api/server.js` with the hardcoded data. Requires its own npm packages for express
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
% curl -i http://localhost:3080/rest/emsespSettings
|
||||
```
|
||||
|
||||
or from a browser use port 3000 since `setupProxy.js` is redirecting, like http://172.22.227.82:3000/rest/emsespSettings
|
||||
|
||||
http://172.22.227.82:3090/es/log?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInZlcnNpb24iOiIzLjAuMmIwIn0.MsHSgoJKI1lyYz77EiT5ZN3ECMrb4mPv9FNy3udq0TU
|
||||
|
||||
Testing the EventSource/SSE use http://172.22.227.82:3090/es/log
|
||||
|
||||
## To Do
|
||||
|
||||
- add filter rule to prevent from exposing yourself to malicious attacks when running the dev server(<https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a>)
|
||||
To set it up it do run `npm install` in the `mock-api` folder, then from the `interface` folder run `npm run standalone`. This will start the mock API server on port 3080 using data from `mock-api/server.js` and the web server runs on port 3000.
|
||||
|
||||
1770
mock-api/package-lock.json
generated
1770
mock-api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,11 +11,11 @@
|
||||
"author": "proddy",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@msgpack/msgpack": "^2.7.2",
|
||||
"@msgpack/msgpack": "^2.8.0",
|
||||
"compression": "^1.7.4",
|
||||
"express": "^4.18.1",
|
||||
"express-sse": "^0.5.3",
|
||||
"nodemon": "^2.0.16",
|
||||
"ws": "^8.7.0"
|
||||
"nodemon": "^2.0.20",
|
||||
"ws": "^8.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,6 @@ settings = {
|
||||
syslog_mark_interval: 0,
|
||||
syslog_host: '192.168.1.4',
|
||||
syslog_port: 514,
|
||||
master_thermostat: 0,
|
||||
shower_timer: true,
|
||||
shower_alert: true,
|
||||
shower_alert_trigger: 7,
|
||||
@@ -348,18 +347,21 @@ const emsesp_devices = {
|
||||
d: 23,
|
||||
p: 77,
|
||||
s: 'Thermostat (RC20/Moduline 300)',
|
||||
t: 'thermostat1',
|
||||
},
|
||||
{
|
||||
i: 2,
|
||||
d: 8,
|
||||
p: 123,
|
||||
s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)',
|
||||
t: 'boiler',
|
||||
},
|
||||
{
|
||||
i: 4,
|
||||
d: 16,
|
||||
p: 165,
|
||||
s: 'Thermostat (RC100/Moduline 1000/1010)',
|
||||
t: 'thermostat2',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -593,13 +595,13 @@ const emsesp_deviceentities_1 = [
|
||||
m: 0,
|
||||
w: false,
|
||||
},
|
||||
{
|
||||
v: 'test data',
|
||||
n: 'test',
|
||||
id: 'test',
|
||||
m: 0,
|
||||
w: false,
|
||||
},
|
||||
// {
|
||||
// v: 'test data',
|
||||
// n: 'test',
|
||||
// id: 'test',
|
||||
// m: 0,
|
||||
// w: false,
|
||||
// },
|
||||
{
|
||||
v: 'roomTemp',
|
||||
id: 'hc1/HA climate config creation',
|
||||
@@ -1133,7 +1135,7 @@ rest_server.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
|
||||
// EMS-ESP API specific
|
||||
const emsesp_info = {
|
||||
System: {
|
||||
version: '3.x.x',
|
||||
version: '3.4.2',
|
||||
uptime: '001+06:40:34.018',
|
||||
'uptime (seconds)': 110434,
|
||||
freemem: 131,
|
||||
@@ -1225,9 +1227,8 @@ rest_server.get(GET_CUSTOMIZATIONS_ENDPOINT, (req, res) => {
|
||||
|
||||
// start server
|
||||
const expressServer = rest_server.listen(port, () =>
|
||||
console.log(`Mock server for EMS-ESP is up and running at http://localhost:${port}`),
|
||||
console.log(`EMS-ESP REST API server running on http://localhost:${port}/api`),
|
||||
)
|
||||
console.log(`EMS-ESP Rest API listening to http://localhost:${port}/api`)
|
||||
|
||||
// start websocket server
|
||||
const websocketServer = new WebSocket.Server({
|
||||
|
||||
@@ -29,6 +29,7 @@ build_flags =
|
||||
-D NO_GLOBAL_ARDUINOOTA
|
||||
-D ARDUINOJSON_ENABLE_STD_STRING=1
|
||||
-D ARDUINOJSON_USE_DOUBLE=0
|
||||
-D CONFIG_UART_ISR_IN_IRAM
|
||||
|
||||
unbuild_flags =
|
||||
${common.core_unbuild_flags}
|
||||
@@ -51,7 +52,7 @@ check_flags =
|
||||
[env:ci]
|
||||
extra_scripts = scripts/rename_fw.py
|
||||
board = esp32dev
|
||||
platform = espressif32@3.5.0
|
||||
platform = espressif32
|
||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
||||
build_flags = ${common.build_flags}
|
||||
build_unflags = ${common.unbuild_flags}
|
||||
@@ -61,7 +62,7 @@ extra_scripts =
|
||||
pre:scripts/build_interface.py
|
||||
scripts/rename_fw.py
|
||||
board = esp32dev
|
||||
platform = espressif32@3.5.0
|
||||
platform = espressif32
|
||||
board_build.partitions = esp32_partition_app1984k_spiffs64k.csv
|
||||
build_flags = ${common.build_flags}
|
||||
build_unflags = ${common.unbuild_flags}
|
||||
|
||||
@@ -29,3 +29,15 @@ Authorization: Bearer {{token}}
|
||||
"entity" : "seltemp",
|
||||
"value" : 21.0
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
POST http://10.10.10.134/api
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.2bHpWya2C7Q12WjNUBD6_7N3RCD7CMl-EGhyQVzFdDg
|
||||
|
||||
{
|
||||
"device" : "boiler",
|
||||
"entity" : "wwtapactivated",
|
||||
"value" : "on"
|
||||
}
|
||||
@@ -403,12 +403,19 @@ void AnalogSensor::publish_values(const bool force) {
|
||||
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.gpio());
|
||||
config["val_tpl"] = str;
|
||||
|
||||
snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str());
|
||||
snprintf(str, sizeof(str), "analog_sensor_%s", sensor.name().c_str());
|
||||
config["object_id"] = str;
|
||||
|
||||
snprintf(str, sizeof(str), "%s", sensor.name().c_str());
|
||||
config["name"] = str;
|
||||
|
||||
snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio());
|
||||
config["uniq_id"] = str;
|
||||
|
||||
if (sensor.uom() != DeviceValueUOM::NONE) {
|
||||
config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom());
|
||||
}
|
||||
|
||||
JsonObject dev = config.createNestedObject("dev");
|
||||
JsonArray ids = dev.createNestedArray("ids");
|
||||
ids.add("ems-esp");
|
||||
|
||||
@@ -276,7 +276,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
||||
}
|
||||
}
|
||||
|
||||
// call the function baesed on type
|
||||
// call the function based on type
|
||||
if (cf->cmdfunction_json_) {
|
||||
return_code = ((cf->cmdfunction_json_)(value, id, output)) ? CommandRet::OK : CommandRet::ERROR;
|
||||
}
|
||||
|
||||
@@ -227,10 +227,6 @@ void EMSESPShell::add_console_commands() {
|
||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||
shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
|
||||
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
|
||||
char buffer[4];
|
||||
shell.printfln(F_(master_thermostat_fmt),
|
||||
settings.master_thermostat == 0 ? read_flash_string(F_(auto)).c_str()
|
||||
: Helpers::hextoa(buffer, settings.master_thermostat));
|
||||
shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str());
|
||||
});
|
||||
});
|
||||
@@ -261,23 +257,6 @@ void EMSESPShell::add_console_commands() {
|
||||
}
|
||||
});
|
||||
|
||||
commands->add_command(ShellContext::MAIN,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(set), F_(master), F_(thermostat)},
|
||||
flash_string_vector{F_(deviceid_mandatory)},
|
||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||
uint8_t value = Helpers::hextoint(arguments.front().c_str());
|
||||
EMSESP::webSettingsService.update(
|
||||
[&](WebSettings & settings) {
|
||||
settings.master_thermostat = value;
|
||||
EMSESP::actual_master_thermostat(value); // set the internal value too
|
||||
char buffer[5];
|
||||
shell.printfln(F_(master_thermostat_fmt), !value ? read_flash_string(F_(auto)).c_str() : Helpers::hextoa(buffer, value));
|
||||
return StateUpdateResult::CHANGED;
|
||||
},
|
||||
"local");
|
||||
});
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
commands->add_command(ShellContext::MAIN,
|
||||
CommandFlags::USER,
|
||||
@@ -419,7 +398,7 @@ void EMSESPShell::add_console_commands() {
|
||||
shell.print(F("Available commands are: "));
|
||||
Command::show(shell, device_type, false); // non-verbose mode
|
||||
} else if (return_code != CommandRet::OK) {
|
||||
shell.println(F("Bad syntax"));
|
||||
shell.printfln(F("Bad syntax (error code %d)"), return_code);
|
||||
}
|
||||
},
|
||||
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
|
||||
|
||||
@@ -497,7 +497,10 @@ void DallasSensor::publish_values(const bool force) {
|
||||
snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id().c_str());
|
||||
config["val_tpl"] = str;
|
||||
|
||||
snprintf(str, sizeof(str), "Temperature Sensor %s", sensor.name().c_str());
|
||||
snprintf(str, sizeof(str), "temperature_sensor_%s", sensor.name().c_str());
|
||||
config["object_id"] = str;
|
||||
|
||||
snprintf(str, sizeof(str), "%s", sensor.name().c_str());
|
||||
config["name"] = str;
|
||||
|
||||
snprintf(str, sizeof(str), "dallasensor_%s", sensor.id().c_str());
|
||||
|
||||
@@ -52,10 +52,6 @@
|
||||
#define EMSESP_DEFAULT_TRACELOG_RAW false
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_MASTER_THERMOSTAT
|
||||
#define EMSESP_DEFAULT_MASTER_THERMOSTAT 0 // not set
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_SHOWER_TIMER
|
||||
#define EMSESP_DEFAULT_SHOWER_TIMER false
|
||||
#endif
|
||||
|
||||
@@ -42,11 +42,12 @@
|
||||
{173, DeviceType::BOILER, F("Geo 5xx"), DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
|
||||
{195, DeviceType::BOILER, F("Condens 5000i/Greenstar 8000"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{203, DeviceType::BOILER, F("Logamax U122/Cerapur"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{206, DeviceType::BOILER, F("Ecomline Excellent"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{208, DeviceType::BOILER, F("Logamax Plus/GB192/Condens GC9000"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{210, DeviceType::BOILER, F("Cascade MC400"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{211, DeviceType::BOILER, F("EasyControl Adapter"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{228, DeviceType::BOILER, F("Alternative Heatsource"), DeviceFlags::EMS_DEVICE_FLAG_AM200},
|
||||
{234, DeviceType::BOILER, F("Logamax Plus GB122/Condense 2300"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{206, DeviceType::BOILER, F("Ecomline Excellent"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// Controllers - 0x09 / 0x10 / 0x50
|
||||
{ 68, DeviceType::CONTROLLER, F("BC10/RFM20"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||
@@ -111,6 +112,9 @@
|
||||
{191, DeviceType::THERMOSTAT, F("FR120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model
|
||||
{192, DeviceType::THERMOSTAT, F("FW120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
|
||||
|
||||
// Thermostat remote - 0x38
|
||||
{200, DeviceType::THERMOSTAT, F("RC100H"), DeviceFlags::EMS_DEVICE_FLAG_RC100H},
|
||||
|
||||
// Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww)
|
||||
{ 73, DeviceType::SOLAR, F("SM10"), DeviceFlags::EMS_DEVICE_FLAG_SM10},
|
||||
{101, DeviceType::SOLAR, F("ISM1"), DeviceFlags::EMS_DEVICE_FLAG_ISM},
|
||||
@@ -128,11 +132,12 @@
|
||||
{161, DeviceType::MIXER, F("MM200"), DeviceFlags::EMS_DEVICE_FLAG_MMPLUS},
|
||||
{204, DeviceType::MIXER, F("MP100"), DeviceFlags::EMS_DEVICE_FLAG_MP}, // pool
|
||||
|
||||
// Heat Pumps - 0x38
|
||||
{200, DeviceType::HEATPUMP, F("HP Module"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{248, DeviceType::HEATPUMP, F("Hybrid Manager HM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
// Heat Pumps - 0x38?
|
||||
{252, DeviceType::HEATPUMP, F("HP Module"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// Heat Pumps - 0x53
|
||||
{248, DeviceType::HEATPUMP, F("Hybrid Manager HM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// Connect devices - 0x02
|
||||
{171, DeviceType::CONNECT, F("OpenTherm Converter"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{205, DeviceType::CONNECT, F("Moduline Easy Connect"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
@@ -145,6 +150,9 @@
|
||||
// Switches - 0x11
|
||||
{ 71, DeviceType::SWITCH, F("WM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// EM10 error contact and analog flowtemp control- 0x12
|
||||
{ 74, DeviceType::GATEWAY, F("Error Module EM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// Gateways - 0x48
|
||||
{189, DeviceType::GATEWAY, F("KM200/MB LAN 2"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -131,7 +131,7 @@ class Boiler : public EMSdevice {
|
||||
uint32_t burn2WorkMin_; // burner stage 2 operating time
|
||||
uint32_t heatWorkMin_; // Total heat operating time
|
||||
uint32_t UBAuptime_; // Total UBA working hours
|
||||
char lastCode_[50]; // last error code
|
||||
char lastCode_[55]; // last error code
|
||||
char serviceCode_[4]; // 3 character status/service code
|
||||
uint16_t serviceCodeNumber_; // error/service code
|
||||
uint8_t emergencyOps_;
|
||||
@@ -198,6 +198,38 @@ class Boiler : public EMSdevice {
|
||||
// Pool unit
|
||||
int8_t poolSetTemp_;
|
||||
|
||||
// Alternative Heatsource AM200
|
||||
int16_t cylTopTemp_; // TB1
|
||||
int16_t cylCenterTemp_; // TB2
|
||||
int16_t cylBottomTemp_; // TB3
|
||||
int16_t aFlowTemp_; // TA1
|
||||
int16_t aRetTemp_; // TR1
|
||||
uint8_t aPumpMod_; // PR1 - percent
|
||||
// uint8_t valveByPass_; // VR2
|
||||
uint8_t valveBuffer_; // VB1
|
||||
uint8_t valveReturn_; // VR1
|
||||
// uint8_t heatSource_; // OEV
|
||||
// Settings:
|
||||
uint8_t vr2Config_; // pos 12: off(00)/Keelbypass(01)/(hc1pump(02) only standalone)
|
||||
uint8_t ahsActivated_; // pos 00: Alternate heat source activation: No(00),Yes(01)
|
||||
uint8_t aPumpConfig_; // pos 04: Buffer primary pump->Config pump: No(00),Yes(01)
|
||||
uint8_t aPumpSignal_; // pos 03: Output for PR1 pump: On/Off(00),PWM(01),PWM invers(02)
|
||||
uint8_t aPumpMin_; // pos 21: Min output pump PR1 (%)
|
||||
uint8_t tempRise_; // pos 01: AHS return temp rise: No(00),Yes(01) (mixer VR1)
|
||||
uint8_t setReturnTemp_; // pos 06: Set temp return (°C) (VR1)
|
||||
uint16_t mixRuntime_; // pos 10/11?: Mixer run time (s) (VR1)
|
||||
// uint8_t setFlowTemp_; // pos 07: Set flow temp AHS (°C) (Buffer)
|
||||
uint8_t bufBypass_; // pos 02: Puffer bypass: No(00), Mischer(01), Ventil(02) (Buffer)
|
||||
uint16_t bufMixRuntime_; // pos 8/9: Bypass mixer run time: [time] (s) (Buffer)
|
||||
uint8_t bufConfig_; // pos 20: Konfig WW-Speicher Monovalent(01), Bivalent(02) (buffer)
|
||||
uint8_t blockMode_; // pos 16: Config htg. blocking mode: No(00),Automatic(01),Always block02) (blocking)
|
||||
uint8_t blockTerm_; // pos 17: Config of block terminal: NO(00), NC(01)
|
||||
int8_t blockHyst_; // pos 14?: Hyst. for bolier block (K)
|
||||
uint8_t releaseWait_; // pos 15: Boiler release wait time (min)
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat
|
||||
* thermostat always overwrites settings in boiler
|
||||
@@ -242,10 +274,14 @@ class Boiler : public EMSdevice {
|
||||
void process_HpOutdoor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_HpPool(std::shared_ptr<const Telegram> telegram);
|
||||
void process_HybridHp(std::shared_ptr<const Telegram> telegram);
|
||||
void process_amTempMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_amStatusMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_amSettingMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_amCommandMessage(std::shared_ptr<const Telegram> telegram);
|
||||
void process_amExtraMessage(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
// commands - none of these use the additional id parameter
|
||||
bool set_ww_mode(const char * value, const int8_t id);
|
||||
bool set_ww_mode1(const char * value, const int8_t id);
|
||||
bool set_ww_activated(const char * value, const int8_t id);
|
||||
bool set_tapwarmwater_activated(const char * value, const int8_t id);
|
||||
bool set_ww_onetime(const char * value, const int8_t id);
|
||||
@@ -282,6 +318,24 @@ class Boiler : public EMSdevice {
|
||||
bool set_pool_temp(const char * value, const int8_t id);
|
||||
bool set_emergency_temp(const char * value, const int8_t id);
|
||||
bool set_emergency_ops(const char * value, const int8_t id);
|
||||
|
||||
bool set_vr2Config(const char * value, const int8_t id); // pos 12: off(00)/Keelbypass(01)/(hc1pump(02) only standalone)
|
||||
bool set_ahsActivated(const char * value, const int8_t id); // pos 00: Alternate heat source activation: No(00),Yes(01)
|
||||
bool set_aPumpConfig(const char * value, const int8_t id); // pos 04: Buffer primary pump->Config pump: No(00),Yes(01)
|
||||
bool set_aPumpSignal(const char * value, const int8_t id); // pos 03: Output for PR1 pump: On/Off(00),PWM(01),PWM invers(02)
|
||||
bool set_aPumpMin(const char * value, const int8_t id); // pos 21: Min output pump PR1 (%)
|
||||
bool set_tempRise(const char * value, const int8_t id); // pos 01: AHS return temp rise: No(00),Yes(01) (mixer VR1)
|
||||
bool set_setReturnTemp(const char * value, const int8_t id); // pos 06: Set temp return (°C) (VR1)
|
||||
bool set_mixRuntime(const char * value, const int8_t id); // pos 10/11?: Mixer run time (s) (VR1)
|
||||
bool set_setFlowTemp(const char * value, const int8_t id); // pos 07: Set flow temp AHS (°C) (Buffer)
|
||||
bool set_bufBypass(const char * value, const int8_t id); // pos 02: Puffer bypass: No(00), Mischer(01), Ventil(02) (Buffer)
|
||||
bool set_bufMixRuntime(const char * value, const int8_t id); // pos 8/9: Bypass mixer run time: [time] (s) (Buffer)
|
||||
bool set_bufConfig(const char * value, const int8_t id); // pos 20: Konfig WW-Speicher Monovalent(01), Bivalent(02) (buffer)
|
||||
bool set_blockMode(const char * value, const int8_t id); // pos 16: Config htg. blocking mode: No(00),Automatic(01),Always block02) (blocking)
|
||||
bool set_blockTerm(const char * value, const int8_t id); // pos 17: Config of block terminal: NO(00), NC(01)
|
||||
bool set_blockHyst(const char * value, const int8_t id); // pos 14?: Hyst. for bolier block (K)
|
||||
bool set_releaseWait(const char * value, const int8_t id); // pos 15: Boiler release wait time (min)
|
||||
|
||||
/*
|
||||
bool set_hybridStrategy(const char * value, const int8_t id);
|
||||
bool set_switchOverTemp(const char * value, const int8_t id);
|
||||
|
||||
@@ -27,7 +27,7 @@ Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
// IVT broadcasts Thermostat time from controller (0x09) if display is off.
|
||||
if ((flags & 0x0F) == EMS_DEVICE_FLAG_IVT) {
|
||||
register_telegram_type(0x06, F("RCTime"), false, MAKE_PF_CB(process_dateTime));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ void Controller::process_dateTime(std::shared_ptr<const Telegram> telegram) {
|
||||
return;
|
||||
}
|
||||
char newdatetime[sizeof(dateTime_)];
|
||||
// publish as dd.mm.yyyy hh:mmF
|
||||
// publish as dd.mm.yyyy hh:mm
|
||||
snprintf(newdatetime,
|
||||
sizeof(dateTime_),
|
||||
"%02d.%02d.%04d %02d:%02d",
|
||||
|
||||
@@ -29,7 +29,7 @@ Generic::Generic(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
|
||||
// RF-Sensor 0x40 sending temperature in telegram 0x435, see https://github.com/emsesp/EMS-ESP32/issues/103
|
||||
if (device_id == 0x40) {
|
||||
register_telegram_type(0x435, F("RFSensorMessage"), false, MAKE_PF_CB(process_RFSensorMessage));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &rfTemp_, DeviceValueType::SHORT, FL_(div10), FL_(RFTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &rfTemp_, DeviceValueType::SHORT, FL_(div10), FL_(RFTemp), DeviceValueUOM::DEGREES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP);
|
||||
Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
// telegram handlers
|
||||
register_telegram_type(0x042B, F("HP1"), true, MAKE_PF_CB(process_HPMonitor1));
|
||||
register_telegram_type(0x047B, F("HP2"), true, MAKE_PF_CB(process_HPMonitor2));
|
||||
register_telegram_type(0x042B, F("HP1"), false, MAKE_PF_CB(process_HPMonitor1));
|
||||
register_telegram_type(0x047B, F("HP2"), false, MAKE_PF_CB(process_HPMonitor2));
|
||||
|
||||
// device values
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &airHumidity_, DeviceValueType::UINT, FL_(div2), FL_(airHumidity), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &dewTemperature_, DeviceValueType::UINT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, nullptr, FL_(airHumidity), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dewTemperature_, DeviceValueType::UINT, nullptr, FL_(dewTemperature), DeviceValueUOM::DEGREES);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,9 +30,9 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_MP) {
|
||||
register_telegram_type(0x5BA, F("HpPoolStatus"), true, MAKE_PF_CB(process_HpPoolStatus));
|
||||
type_ = Type::MP;
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &poolTemp_, DeviceValueType::SHORT, FL_(div10), FL_(poolTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &poolShunt_, DeviceValueType::UINT, nullptr, FL_(poolShunt), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolTemp_, DeviceValueType::SHORT, FL_(div10), FL_(poolTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShuntStatus_, DeviceValueType::ENUM, FL_(enum_shunt), FL_(poolShuntStatus), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &poolShunt_, DeviceValueType::UINT, nullptr, FL_(poolShunt), DeviceValueUOM::PERCENT);
|
||||
}
|
||||
|
||||
// EMS+
|
||||
|
||||
@@ -134,37 +134,43 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
}
|
||||
|
||||
// common solar values for all modules (except dhw)
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylBottomTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &pumpWorkTime_, DeviceValueType::TIME, nullptr, FL_(pumpWorkTime), DeviceValueUOM::MINUTES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorTemp_, DeviceValueType::SHORT, FL_(div10), FL_(collectorTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylBottomTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylBottomTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump_, DeviceValueType::BOOL, nullptr, FL_(solarPump), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pumpWorkTime_, DeviceValueType::TIME, nullptr, FL_(pumpWorkTime), DeviceValueUOM::MINUTES);
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &cylMaxTemp_, DeviceValueType::UINT, nullptr, FL_(cylMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cylMaxTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
|
||||
DeviceValueTAG::TAG_DEVICE_DATA, &cylMaxTemp_, DeviceValueType::UINT, nullptr, FL_(cylMaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cylMaxTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
|
||||
|
||||
// values per device flag
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &solarPumpMinMod_, DeviceValueType::UINT, nullptr, FL_(pumpMinMod), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_PumpMinMod));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpMinMod_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(pumpMinMod),
|
||||
DeviceValueUOM::PERCENT,
|
||||
MAKE_CF_CB(set_PumpMinMod));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpTurnonDiff_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(solarPumpTurnonDiff),
|
||||
DeviceValueUOM::DEGREES_R,
|
||||
MAKE_CF_CB(set_TurnonDiff));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpTurnoffDiff_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(solarPumpTurnoffDiff),
|
||||
DeviceValueUOM::DEGREES_R,
|
||||
MAKE_CF_CB(set_TurnoffDiff));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &solarPower_, DeviceValueType::SHORT, nullptr, FL_(solarPower), DeviceValueUOM::W);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &maxFlow_, DeviceValueType::UINT, FL_(div10), FL_(maxFlow), DeviceValueUOM::LMIN, MAKE_CF_CB(set_SM10MaxFlow));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPower_, DeviceValueType::SHORT, nullptr, FL_(solarPower), DeviceValueUOM::W);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_DEVICE_DATA, &maxFlow_, DeviceValueType::UINT, FL_(div10), FL_(maxFlow), DeviceValueUOM::LMIN, MAKE_CF_CB(set_SM10MaxFlow));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA_WW,
|
||||
&wwMinTemp_,
|
||||
DeviceValueType::UINT,
|
||||
@@ -172,7 +178,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
FL_(wwMinTemp),
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_wwMinTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarIsEnabled_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
@@ -182,102 +188,122 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
|
||||
/* unknown values for testing and logging. Used by MichaelDvP
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &setting3_, DeviceValueType::UINT, nullptr, FL_(setting3), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMaxTemp));
|
||||
DeviceValueTAG::TAG_DEVICE_DATA, &setting3_, DeviceValueType::UINT, nullptr, FL_(setting3), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMaxTemp));
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &setting4_, DeviceValueType::UINT, nullptr, FL_(setting4), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMinTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &data11_, DeviceValueType::UINT, nullptr, FL_(data11), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &data12_, DeviceValueType::UINT, nullptr, FL_(data12), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &data1_, DeviceValueType::UINT, nullptr, FL_(data1), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &data0_, DeviceValueType::UINT, nullptr, FL_(data0), DeviceValueUOM::NONE);
|
||||
DeviceValueTAG::TAG_DEVICE_DATA, &setting4_, DeviceValueType::UINT, nullptr, FL_(setting4), DeviceValueUOM::NONE, MAKE_CF_CB(set_CollectorMinTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data11_, DeviceValueType::UINT, nullptr, FL_(data11), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data12_, DeviceValueType::UINT, nullptr, FL_(data12), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data1_, DeviceValueType::UINT, nullptr, FL_(data1), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &data0_, DeviceValueType::UINT, nullptr, FL_(data0), DeviceValueUOM::NONE);
|
||||
*/
|
||||
}
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
|
||||
}
|
||||
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPumpMod_, DeviceValueType::UINT, nullptr, FL_(solarPumpMod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpMinMod_,
|
||||
DeviceValueType::UINT,
|
||||
FL_(mul5),
|
||||
FL_(pumpMinMod),
|
||||
DeviceValueUOM::PERCENT,
|
||||
MAKE_CF_CB(set_PumpMinMod));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpTurnonDiff_,
|
||||
DeviceValueType::UINT,
|
||||
FL_(div10),
|
||||
FL_(solarPumpTurnonDiff),
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_TurnonDiff));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpTurnoffDiff_,
|
||||
DeviceValueType::UINT,
|
||||
FL_(div10),
|
||||
FL_(solarPumpTurnoffDiff),
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_TurnoffDiff));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &collector2Temp_, DeviceValueType::SHORT, FL_(div10), FL_(collector2Temp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &m1Power_, DeviceValueType::UINT, nullptr, FL_(m1Power), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump2_, DeviceValueType::BOOL, nullptr, FL_(solarPump2), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump2Mod_, DeviceValueType::UINT, nullptr, FL_(solarPump2Mod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylBottomTemp2_, DeviceValueType::SHORT, FL_(div10), FL_(cyl2BottomTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &heatExchangerTemp_, DeviceValueType::SHORT, FL_(div10), FL_(heatExchangerTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylPumpMod_, DeviceValueType::UINT, nullptr, FL_(cylPumpMod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collector2Temp_, DeviceValueType::SHORT, FL_(div10), FL_(collector2Temp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylMiddleTemp_, DeviceValueType::SHORT, FL_(div10), FL_(cylMiddleTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retHeatAssist_, DeviceValueType::SHORT, FL_(div10), FL_(retHeatAssist), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Valve_, DeviceValueType::BOOL, nullptr, FL_(m1Valve), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1Power_, DeviceValueType::UINT, nullptr, FL_(m1Power), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2_, DeviceValueType::BOOL, nullptr, FL_(solarPump2), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &solarPump2Mod_, DeviceValueType::UINT, nullptr, FL_(solarPump2Mod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylBottomTemp2_, DeviceValueType::SHORT, FL_(div10), FL_(cyl2BottomTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&heatExchangerTemp_,
|
||||
DeviceValueType::SHORT,
|
||||
FL_(div10),
|
||||
FL_(heatExchangerTemp),
|
||||
DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylPumpMod_, DeviceValueType::UINT, nullptr, FL_(cylPumpMod), DeviceValueUOM::PERCENT);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &valveStatus_, DeviceValueType::BOOL, nullptr, FL_(valveStatus), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, nullptr, FL_(cylHeated), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, nullptr, FL_(collectorShutdown), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&collectorMaxTemp_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(collectorMaxTemp),
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_CollectorMaxTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&collectorMinTemp_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(collectorMinTemp),
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_CollectorMinTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &energyToday_, DeviceValueType::ULONG, nullptr, FL_(energyToday), DeviceValueUOM::WH);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &pump2WorkTime_, DeviceValueType::TIME, nullptr, FL_(pump2WorkTime), DeviceValueUOM::MINUTES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &m1WorkTime_, DeviceValueType::TIME, nullptr, FL_(m1WorkTime), DeviceValueUOM::MINUTES);
|
||||
// register_device_value(DeviceValueTAG::TAG_NONE, &cyl2MaxTemp_, DeviceValueType::UINT, nullptr, FL_(cyl2MaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cyl2MaxTemp));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), FL_(energyLastHour), DeviceValueUOM::WH);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyToday_, DeviceValueType::ULONG, nullptr, FL_(energyToday), DeviceValueUOM::WH);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &energyTotal_, DeviceValueType::ULONG, FL_(div10), FL_(energyTotal), DeviceValueUOM::KWH);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pump2WorkTime_, DeviceValueType::TIME, nullptr, FL_(pump2WorkTime), DeviceValueUOM::MINUTES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &m1WorkTime_, DeviceValueType::TIME, nullptr, FL_(m1WorkTime), DeviceValueUOM::MINUTES);
|
||||
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cyl2MaxTemp_, DeviceValueType::UINT, nullptr, FL_(cyl2MaxTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_cyl2MaxTemp));
|
||||
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&heatTransferSystem_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
FL_(heatTransferSystem),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_heatTransferSystem));
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &externalCyl_, DeviceValueType::BOOL, nullptr, FL_(externalCyl), DeviceValueUOM::NONE, MAKE_CF_CB(set_externalCyl));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&externalCyl_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
FL_(externalCyl),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_externalCyl));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&thermalDisinfect_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
FL_(thermalDisinfect),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_thermalDisinfect));
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &heatMetering_, DeviceValueType::BOOL, nullptr, FL_(heatMetering), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatMetering));
|
||||
register_device_value(
|
||||
DeviceValueTAG::TAG_NONE, &solarIsEnabled_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE, MAKE_CF_CB(set_solarEnabled));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&heatMetering_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
FL_(heatMetering),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_heatMetering));
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarIsEnabled_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
FL_(activated),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_solarEnabled));
|
||||
|
||||
// telegram 0x035A
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpMode_,
|
||||
DeviceValueType::ENUM,
|
||||
FL_(enum_solarmode),
|
||||
@@ -285,7 +311,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_solarMode));
|
||||
register_device_value( // pump kick for vacuum collector, 00=off
|
||||
DeviceValueTAG::TAG_NONE,
|
||||
DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPumpKick_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
@@ -293,7 +319,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_solarPumpKick));
|
||||
register_device_value( // system does not use antifreeze, 00=off
|
||||
DeviceValueTAG::TAG_NONE,
|
||||
DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&plainWaterMode_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
@@ -301,7 +327,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_plainWaterMode));
|
||||
register_device_value( // double Match Flow, 00=off
|
||||
DeviceValueTAG::TAG_NONE,
|
||||
DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&doubleMatchFlow_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
@@ -309,21 +335,21 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_doubleMatchFlow));
|
||||
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPump2MinMod_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(pump2MinMod),
|
||||
DeviceValueUOM::PERCENT,
|
||||
MAKE_CF_CB(set_Pump2MinMod));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPump2TurnonDiff_,
|
||||
DeviceValueType::UINT,
|
||||
FL_(div10),
|
||||
FL_(solarPump2TurnonDiff),
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_TurnonDiff2));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPump2TurnoffDiff_,
|
||||
DeviceValueType::UINT,
|
||||
FL_(div10),
|
||||
@@ -331,7 +357,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
DeviceValueUOM::DEGREES,
|
||||
MAKE_CF_CB(set_TurnoffDiff2));
|
||||
register_device_value( // pump kick for vacuum collector, 00=off
|
||||
DeviceValueTAG::TAG_NONE,
|
||||
DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&solarPump2Kick_,
|
||||
DeviceValueType::BOOL,
|
||||
nullptr,
|
||||
@@ -340,53 +366,53 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
|
||||
MAKE_CF_CB(set_solarPump2Kick));
|
||||
|
||||
// telegram 0x380
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&climateZone_,
|
||||
DeviceValueType::UINT,
|
||||
nullptr,
|
||||
FL_(climateZone),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_climateZone)); // climate zone identifier
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&collector1Area_,
|
||||
DeviceValueType::USHORT,
|
||||
FL_(div10),
|
||||
FL_(collector1Area),
|
||||
DeviceValueUOM::SQM,
|
||||
MAKE_CF_CB(set_collector1Area)); // Area of collector field 1
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&collector1Type_,
|
||||
DeviceValueType::ENUM,
|
||||
FL_(enum_collectortype),
|
||||
FL_(collector1Type),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_collector1Type)); // Type of collector field 1, 01=flat, 02=vacuum
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&collector2Area_,
|
||||
DeviceValueType::USHORT,
|
||||
FL_(div10),
|
||||
FL_(collector2Area),
|
||||
DeviceValueUOM::SQM,
|
||||
MAKE_CF_CB(set_collector2Area)); // Area of collector field 2
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&collector2Type_,
|
||||
DeviceValueType::ENUM,
|
||||
FL_(enum_collectortype),
|
||||
FL_(collector2Type),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_collector2Type)); // Type of collector field 2, 01=flat, 02=vacuum
|
||||
register_device_value(DeviceValueTAG::TAG_NONE,
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
|
||||
&cylPriority_,
|
||||
DeviceValueType::ENUM,
|
||||
FL_(enum_cylprio),
|
||||
FL_(cylPriority),
|
||||
DeviceValueUOM::NONE,
|
||||
MAKE_CF_CB(set_cylPriority));
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &heatCntFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntFlowTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &heatCntRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntRetTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &heatCnt_, DeviceValueType::UINT, nullptr, FL_(heatCnt), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &swapFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapFlowTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &swapRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapRetTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCntFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntFlowTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCntRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(heatCntRetTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCnt_, DeviceValueType::UINT, nullptr, FL_(heatCnt), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &swapFlowTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapFlowTemp), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &swapRetTemp_, DeviceValueType::USHORT, FL_(div10), FL_(swapRetTemp), DeviceValueUOM::DEGREES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,13 +24,14 @@ REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH);
|
||||
|
||||
Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||
// WM10 module, device_id 0x11
|
||||
register_telegram_type(0x9C, F("WM10MonitorMessage"), false, MAKE_PF_CB(process_WM10MonitorMessage));
|
||||
register_telegram_type(0x9D, F("WM10SetMessage"), false, MAKE_PF_CB(process_WM10SetMessage));
|
||||
register_telegram_type(0x1E, F("WM10TempMessage"), false, MAKE_PF_CB(process_WM10TempMessage));
|
||||
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_NONE, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &activated_, DeviceValueType::BOOL, nullptr, FL_(activated), DeviceValueUOM::NONE);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &flowTempHc_, DeviceValueType::USHORT, FL_(div10), FL_(flowTempHc), DeviceValueUOM::DEGREES);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &status_, DeviceValueType::INT, nullptr, FL_(status), DeviceValueUOM::NONE);
|
||||
}
|
||||
|
||||
// message 0x9D switch on/off
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,7 @@ class Thermostat : public EMSdevice {
|
||||
int16_t roomTemp;
|
||||
int16_t remotetemp; // for readback
|
||||
uint8_t tempautotemp;
|
||||
int8_t remoteseltemp;
|
||||
uint8_t mode;
|
||||
uint8_t modetype;
|
||||
uint8_t summermode;
|
||||
@@ -56,6 +57,7 @@ class Thermostat : public EMSdevice {
|
||||
uint8_t manualtemp;
|
||||
uint8_t summersetmode;
|
||||
uint8_t hpoperatingmode;
|
||||
uint8_t hpoperatingstate;
|
||||
uint8_t roominfluence;
|
||||
uint8_t roominfl_factor;
|
||||
int16_t curroominfl;
|
||||
@@ -80,6 +82,8 @@ class Thermostat : public EMSdevice {
|
||||
char switchtime1[16];
|
||||
char switchtime2[16];
|
||||
uint8_t climate;
|
||||
uint8_t switchonoptimization;
|
||||
uint8_t statusbyte; // from RC300monitor
|
||||
|
||||
// RC 10
|
||||
uint8_t reducehours; // night reduce duration
|
||||
@@ -130,6 +134,7 @@ class Thermostat : public EMSdevice {
|
||||
ON,
|
||||
DAYLOW,
|
||||
DAYMID,
|
||||
REMOTESELTEMP,
|
||||
UNKNOWN
|
||||
|
||||
};
|
||||
@@ -160,6 +165,7 @@ class Thermostat : public EMSdevice {
|
||||
// each thermostat has a list of heating controller type IDs for reading and writing
|
||||
std::vector<uint16_t> monitor_typeids;
|
||||
std::vector<uint16_t> set_typeids;
|
||||
std::vector<uint16_t> set2_typeids;
|
||||
std::vector<uint16_t> timer_typeids;
|
||||
std::vector<uint16_t> timer2_typeids;
|
||||
std::vector<uint16_t> summer_typeids;
|
||||
@@ -190,11 +196,13 @@ class Thermostat : public EMSdevice {
|
||||
uint8_t mixingvalves_; // Number of Mixing Valves: (0x00=0, 0x01=1, 0x02=2)
|
||||
|
||||
int8_t dampedoutdoortemp_;
|
||||
uint16_t tempsensor1_;
|
||||
uint16_t tempsensor2_;
|
||||
int16_t tempsensor1_;
|
||||
int16_t tempsensor2_;
|
||||
int16_t dampedoutdoortemp2_;
|
||||
uint8_t floordrystatus_;
|
||||
uint8_t floordrytemp_;
|
||||
uint8_t dewtemperature_;
|
||||
uint8_t humidity_;
|
||||
|
||||
uint8_t wwExtra1_; // wwExtra active for wwSystem 1
|
||||
uint8_t wwExtra2_;
|
||||
@@ -217,6 +225,8 @@ class Thermostat : public EMSdevice {
|
||||
uint8_t wwDailyHeating_;
|
||||
uint8_t wwDailyHeatTime_;
|
||||
uint8_t wwWhenModeOff_;
|
||||
char wwHoliday_[26];
|
||||
char wwVacation_[26];
|
||||
|
||||
// HybridHP
|
||||
uint8_t hybridStrategy_; // co2 = 1, cost = 2, temperature = 3, mix = 4
|
||||
@@ -357,6 +367,7 @@ class Thermostat : public EMSdevice {
|
||||
void process_CRFMonitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300Set(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300Set2(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300Summer(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300Summer2(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
|
||||
@@ -373,6 +384,9 @@ class Thermostat : public EMSdevice {
|
||||
void process_JunkersRemoteMonitor(std::shared_ptr<const Telegram> telegram);
|
||||
void process_JunkersHybridSettings(std::shared_ptr<const Telegram> telegram);
|
||||
void process_JunkersSetMixer(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RemoteTemp(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RemoteHumidity(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RemoteCorrection(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
// internal helper functions
|
||||
bool set_mode_n(const uint8_t mode, const uint8_t hc_num);
|
||||
@@ -412,7 +426,6 @@ class Thermostat : public EMSdevice {
|
||||
bool set_vacreducetemp(const char * value, const int8_t id);
|
||||
bool set_vacreducemode(const char * value, const int8_t id);
|
||||
bool set_nofrostmode(const char * value, const int8_t id);
|
||||
|
||||
bool set_remotetemp(const char * value, const int8_t id);
|
||||
bool set_roominfluence(const char * value, const int8_t id);
|
||||
bool set_roominfl_factor(const char * value, const int8_t id);
|
||||
@@ -426,6 +439,8 @@ class Thermostat : public EMSdevice {
|
||||
bool set_controlmode(const char * value, const int8_t id);
|
||||
bool set_wwprio(const char * value, const int8_t id);
|
||||
bool set_fastheatup(const char * value, const int8_t id);
|
||||
bool set_switchonoptimization(const char * value, const int8_t id);
|
||||
bool set_remoteseltemp(const char * value, const int8_t id);
|
||||
|
||||
// set functions - these don't use the id/hc, the parameters are ignored
|
||||
bool set_wwmode(const char * value, const int8_t id);
|
||||
@@ -446,6 +461,12 @@ class Thermostat : public EMSdevice {
|
||||
bool set_wwDailyHeating(const char * value, const int8_t id);
|
||||
bool set_wwDailyHeatTime(const char * value, const int8_t id);
|
||||
bool set_wwwhenmodeoff(const char * value, const int8_t id);
|
||||
bool set_wwVacation(const char * value, const int8_t id) {
|
||||
return set_holiday(value, DeviceValueTAG::TAG_WWC1, true);
|
||||
}
|
||||
bool set_wwHoliday(const char * value, const int8_t id) {
|
||||
return set_holiday(value, DeviceValueTAG::TAG_WWC1);
|
||||
}
|
||||
|
||||
bool set_datetime(const char * value, const int8_t id);
|
||||
bool set_minexttemp(const char * value, const int8_t id);
|
||||
|
||||
@@ -114,7 +114,7 @@ std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
|
||||
// returns device_type from a string
|
||||
uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
|
||||
if (!topic) {
|
||||
return DeviceType::UNKNOWN; // nullptr
|
||||
return DeviceType::UNKNOWN;
|
||||
}
|
||||
|
||||
// convert topic to lowercase and compare
|
||||
@@ -244,6 +244,16 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for a tag to create a nest
|
||||
bool EMSdevice::has_tag(const uint8_t tag) const {
|
||||
for (const auto & dv : devicevalues_) {
|
||||
if (dv.tag == tag && tag >= DeviceValueTAG::TAG_HC1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// list of registered device entries
|
||||
// called from the command 'entities'
|
||||
void EMSdevice::list_device_entries(JsonObject & output) const {
|
||||
@@ -469,7 +479,7 @@ void EMSdevice::register_device_value(uint8_t tag,
|
||||
flags |= CommandFlag::MQTT_SUB_FLAG_HC;
|
||||
} else if (tag >= DeviceValueTAG::TAG_WWC1 && tag <= DeviceValueTAG::TAG_WWC10) {
|
||||
flags |= CommandFlag::MQTT_SUB_FLAG_WWC;
|
||||
} else if (tag == DeviceValueTAG::TAG_DEVICE_DATA_WW) {
|
||||
} else if (tag == DeviceValueTAG::TAG_DEVICE_DATA_WW || tag == DeviceValueTAG::TAG_BOILER_DATA_WW) {
|
||||
flags |= CommandFlag::MQTT_SUB_FLAG_WW;
|
||||
}
|
||||
|
||||
@@ -541,7 +551,7 @@ void EMSdevice::publish_value(void * value_p) const {
|
||||
if (dv.value_p == value_p && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) {
|
||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||
if (Mqtt::publish_single2cmd()) {
|
||||
if (dv.tag >= DeviceValueTAG::TAG_HC1 && dv.tag <= DeviceValueTAG::TAG_WWC10) {
|
||||
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
|
||||
snprintf(topic,
|
||||
sizeof(topic),
|
||||
"%s/%s/%s",
|
||||
@@ -563,7 +573,7 @@ void EMSdevice::publish_value(void * value_p) const {
|
||||
}
|
||||
|
||||
int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0;
|
||||
char payload[50] = {'\0'};
|
||||
char payload[55] = {'\0'};
|
||||
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
|
||||
|
||||
switch (dv.type) {
|
||||
@@ -900,11 +910,9 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
||||
JsonObject json = output;
|
||||
int8_t tag = id;
|
||||
|
||||
// check if we have hc or wwc
|
||||
if (id >= 1 && id <= 8) {
|
||||
// check if we have hc or wwc or hs
|
||||
if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) {
|
||||
tag = DeviceValueTAG::TAG_HC1 + id - 1;
|
||||
} else if (id >= 9 && id <= 19) {
|
||||
tag = DeviceValueTAG::TAG_WWC1 + id - 9;
|
||||
}
|
||||
|
||||
// make a copy of the string command for parsing
|
||||
|
||||
@@ -52,6 +52,8 @@ class EMSdevice {
|
||||
static std::string tag_to_string(uint8_t tag);
|
||||
static std::string tag_to_mqtt(uint8_t tag);
|
||||
|
||||
bool has_tag(const uint8_t tag) const;
|
||||
|
||||
inline uint8_t device_id() const {
|
||||
return device_id_;
|
||||
}
|
||||
@@ -307,6 +309,7 @@ class EMSdevice {
|
||||
static constexpr uint8_t EMS_DEVICE_ID_BOILER = 0x08; // fixed device_id for Master Boiler/UBA
|
||||
static constexpr uint8_t EMS_DEVICE_ID_BOILER_1 = 0x70; // fixed device_id for 1st. Cascade Boiler/UBA
|
||||
static constexpr uint8_t EMS_DEVICE_ID_BOILER_F = 0x7F; // fixed device_id for last Cascade Boiler/UBA
|
||||
static constexpr uint8_t EMS_DEVICE_ID_AM200 = 0x60; // fixed device_id for alternative Heating AM200
|
||||
|
||||
// generic type IDs
|
||||
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.
|
||||
@@ -324,6 +327,7 @@ class EMSdevice {
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_HT3 = 3;
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_HEATPUMP = 4;
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_HYBRID = 5;
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_AM200 = 6;
|
||||
|
||||
// Solar Module
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_SM10 = 1;
|
||||
@@ -351,6 +355,7 @@ class EMSdevice {
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_RC100 = 10;
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_JUNKERS = 11;
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_CRF = 12; // CRF200 only monitor
|
||||
static constexpr uint8_t EMS_DEVICE_FLAG_RC100H = 13; // with humidity
|
||||
|
||||
uint8_t count_entities();
|
||||
bool has_entities() const;
|
||||
|
||||
@@ -55,9 +55,9 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_s[] PROGMEM = {
|
||||
|
||||
F_(tag_none), // ""
|
||||
F_(tag_heartbeat), // ""
|
||||
F_(tag_boiler_data), // ""
|
||||
F_(tag_device_data_ww), // "ww"
|
||||
F_(tag_thermostat_data), // ""
|
||||
F_(tag_boiler_data_ww), // "dhw"
|
||||
F_(tag_device_data), // ""
|
||||
F_(tag_device_data_ww), // "dhw"
|
||||
F_(tag_hc1), // "hc1"
|
||||
F_(tag_hc2), // "hc2"
|
||||
F_(tag_hc3), // "hc3"
|
||||
@@ -76,6 +76,7 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_s[] PROGMEM = {
|
||||
F_(tag_wwc8), // "wwc8"
|
||||
F_(tag_wwc9), // "wwc9"
|
||||
F_(tag_wwc10), // "wwc10"
|
||||
F_(tag_ahs), // "ahs"
|
||||
F_(tag_hs1), // "hs1"
|
||||
F_(tag_hs2), // "hs2"
|
||||
F_(tag_hs3), // "hs3"
|
||||
@@ -100,9 +101,9 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_mqtt[] PROGMEM = {
|
||||
|
||||
F_(tag_none), // ""
|
||||
F_(heartbeat), // "heartbeat"
|
||||
F_(tag_boiler_data_mqtt), // ""
|
||||
F_(tag_device_data_ww_mqtt), // "ww"
|
||||
F_(tag_thermostat_data), // ""
|
||||
F_(tag_boiler_data_ww_mqtt), // "ww"
|
||||
F_(tag_device_data), // ""
|
||||
F_(tag_device_data_ww_mqtt), // ""
|
||||
F_(tag_hc1), // "hc1"
|
||||
F_(tag_hc2), // "hc2"
|
||||
F_(tag_hc3), // "hc3"
|
||||
@@ -121,6 +122,7 @@ const __FlashStringHelper * const DeviceValue::DeviceValueTAG_mqtt[] PROGMEM = {
|
||||
F_(tag_wwc8), // "wwc8"
|
||||
F_(tag_wwc9), // "wwc9"
|
||||
F_(tag_wwc10), // "wwc10"
|
||||
F_(tag_ahs), // "ahs"
|
||||
F_(tag_hs1), // "hs1"
|
||||
F_(tag_hs2), // "hs2"
|
||||
F_(tag_hs3), // "hs3"
|
||||
|
||||
@@ -75,9 +75,9 @@ class DeviceValue {
|
||||
enum DeviceValueTAG : uint8_t {
|
||||
TAG_NONE = 0, // wild card
|
||||
TAG_HEARTBEAT,
|
||||
TAG_BOILER_DATA,
|
||||
TAG_BOILER_DATA_WW,
|
||||
TAG_DEVICE_DATA,
|
||||
TAG_DEVICE_DATA_WW,
|
||||
TAG_THERMOSTAT_DATA,
|
||||
TAG_HC1,
|
||||
TAG_HC2,
|
||||
TAG_HC3,
|
||||
@@ -96,6 +96,7 @@ class DeviceValue {
|
||||
TAG_WWC8,
|
||||
TAG_WWC9,
|
||||
TAG_WWC10,
|
||||
TAG_AHS,
|
||||
TAG_HS1,
|
||||
TAG_HS2,
|
||||
TAG_HS3,
|
||||
|
||||
222
src/emsesp.cpp
222
src/emsesp.cpp
@@ -28,9 +28,9 @@ ESP8266React EMSESP::esp8266React(&webServer, &dummyFS);
|
||||
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
||||
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager());
|
||||
#else
|
||||
ESP8266React EMSESP::esp8266React(&webServer, &LITTLEFS);
|
||||
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LITTLEFS, EMSESP::esp8266React.getSecurityManager());
|
||||
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LITTLEFS, EMSESP::esp8266React.getSecurityManager());
|
||||
ESP8266React EMSESP::esp8266React(&webServer, &LittleFS);
|
||||
WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
||||
WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager());
|
||||
#endif
|
||||
|
||||
WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||
@@ -60,7 +60,6 @@ AnalogSensor EMSESP::analogsensor_; // Analog sensors
|
||||
Shower EMSESP::shower_; // Shower logic
|
||||
|
||||
// static/common variables
|
||||
uint8_t EMSESP::actual_master_thermostat_ = EMSESP_DEFAULT_MASTER_THERMOSTAT; // which thermostat leads when multiple found
|
||||
uint16_t EMSESP::watch_id_ = WATCH_ID_NONE; // for when log is TRACE. 0 means no trace set
|
||||
uint8_t EMSESP::watch_ = 0; // trace off
|
||||
uint16_t EMSESP::read_id_ = WATCH_ID_NONE;
|
||||
@@ -168,63 +167,6 @@ void EMSESP::scan_devices() {
|
||||
EMSESP::send_read_request(EMSdevice::EMS_TYPE_UBADevices, EMSdevice::EMS_DEVICE_ID_BOILER);
|
||||
}
|
||||
|
||||
/**
|
||||
* if thermostat master is 0x18 it handles only ww and hc1, hc2..hc8 handled by devices 0x19..0x1F
|
||||
* we send to right device and match all reads to 0x18
|
||||
*/
|
||||
uint8_t EMSESP::check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read) {
|
||||
if (device_id != 0x10 && (device_id < 0x18 || device_id > 0x1F)) {
|
||||
return device_id;
|
||||
}
|
||||
if (actual_master_thermostat_ == 0x18) {
|
||||
uint16_t mon_ids[] = {0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC};
|
||||
uint16_t set_ids[] = {0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF, 0x02C0};
|
||||
uint16_t summer_ids[] = {0x02AF, 0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4, 0x02B5, 0x02B6};
|
||||
uint16_t curve_ids[] = {0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2};
|
||||
uint16_t summer2_ids[] = {0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478};
|
||||
uint16_t master_ids[] = {0x02F5, 0x031B, 0x031D, 0x031E, 0x023A, 0x0267, 0x0240};
|
||||
// look for heating circuits
|
||||
for (uint8_t i = 0; i < sizeof(mon_ids) / 2; i++) {
|
||||
if (type_id == mon_ids[i] || type_id == set_ids[i] || type_id == summer_ids[i] || type_id == curve_ids[i] || type_id == summer2_ids[i]) {
|
||||
if (read) {
|
||||
// receiving telegrams and map all to master thermostat at 0x18 (src manipulated)
|
||||
return 0x18;
|
||||
} else {
|
||||
// sending telegrams to the individual thermostats (dst manipulated)
|
||||
return 0x18 + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// look for ids that are only handled by master
|
||||
for (uint8_t i = 0; i < sizeof(master_ids) / 2; i++) {
|
||||
if (type_id == master_ids[i]) {
|
||||
return 0x18;
|
||||
}
|
||||
}
|
||||
} else if (actual_master_thermostat_ == 0x10) {
|
||||
// Junkers FW200 supports hc1/hc2, hc3/hc4 handled by devices 0x1A...
|
||||
// see https://github.com/emsesp/EMS-ESP32/issues/336
|
||||
uint16_t mon_ids[] = {0x0171, 0x0172};
|
||||
uint16_t set_ids[] = {0x0167, 0x0168};
|
||||
for (uint8_t i = 0; i < sizeof(mon_ids) / 2; i++) {
|
||||
if (type_id == mon_ids[i] || type_id == set_ids[i]) {
|
||||
// reads to master thermostat, writes to remote thermostats
|
||||
return (read ? actual_master_thermostat_ : 0x1A + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return device_id;
|
||||
}
|
||||
|
||||
void EMSESP::actual_master_thermostat(const uint8_t device_id) {
|
||||
actual_master_thermostat_ = device_id;
|
||||
}
|
||||
|
||||
uint8_t EMSESP::actual_master_thermostat() {
|
||||
return actual_master_thermostat_;
|
||||
}
|
||||
|
||||
// to watch both type IDs and deviceIDs
|
||||
void EMSESP::watch_id(uint16_t watch_id) {
|
||||
watch_id_ = watch_id;
|
||||
@@ -560,13 +502,13 @@ void EMSESP::publish_device_values(uint8_t device_type) {
|
||||
bool nested = (Mqtt::is_nested());
|
||||
|
||||
// group by device type
|
||||
if (Mqtt::ha_enabled()) {
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||
// specially for MQTT Discovery
|
||||
// we may have some RETAINED /config topics that reference fields in the data payloads that no longer exist
|
||||
// remove them immediately to prevent HA from complaining
|
||||
// we need to do this first before the data payload is published, and only done once!
|
||||
if (Mqtt::ha_enabled()) {
|
||||
if (emsdevice->ha_config_firstrun()) {
|
||||
emsdevice->ha_config_clear();
|
||||
emsdevice->ha_config_firstrun(false);
|
||||
@@ -575,79 +517,40 @@ void EMSESP::publish_device_values(uint8_t device_type) {
|
||||
emsdevice->mqtt_ha_entity_config_remove();
|
||||
}
|
||||
}
|
||||
|
||||
// if its a boiler, generate json for each group and publish it directly. not nested
|
||||
if (device_type == DeviceType::BOILER) {
|
||||
}
|
||||
}
|
||||
for (uint8_t tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) {
|
||||
JsonObject json_hc = json;
|
||||
bool nest_created = false;
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||
if (nested && !nest_created && emsdevice->has_tag(tag)) {
|
||||
json_hc = doc.createNestedObject(EMSdevice::tag_to_string(tag));
|
||||
nest_created = true;
|
||||
}
|
||||
need_publish |= emsdevice->generate_values(json_hc, tag, false, EMSdevice::OUTPUT_TARGET::MQTT);
|
||||
}
|
||||
}
|
||||
if (need_publish && ((!nested && tag >= DeviceValueTAG::TAG_DEVICE_DATA_WW) || (tag == DeviceValueTAG::TAG_BOILER_DATA_WW))) {
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, tag), json);
|
||||
json = doc.to<JsonObject>();
|
||||
if (emsdevice->generate_values(json, DeviceValueTAG::TAG_BOILER_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT)) {
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_BOILER_DATA), json);
|
||||
}
|
||||
json = doc.to<JsonObject>();
|
||||
if (emsdevice->generate_values(json, DeviceValueTAG::TAG_DEVICE_DATA_WW, false, EMSdevice::OUTPUT_TARGET::MQTT)) {
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_DEVICE_DATA_WW), json);
|
||||
}
|
||||
need_publish = false;
|
||||
}
|
||||
|
||||
// Thermostat
|
||||
else if (device_type == DeviceType::THERMOSTAT) {
|
||||
// only publish the single master thermostat
|
||||
if (emsdevice->device_id() == EMSESP::actual_master_thermostat()) {
|
||||
if (nested) {
|
||||
json = doc.to<JsonObject>();
|
||||
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
|
||||
} else {
|
||||
json = doc.to<JsonObject>();
|
||||
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_THERMOSTAT_DATA, false, EMSdevice::OUTPUT_TARGET::MQTT); // not nested
|
||||
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_DEVICE_DATA_WW, false, EMSdevice::OUTPUT_TARGET::MQTT);
|
||||
if (need_publish) {
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json);
|
||||
}
|
||||
for (uint8_t hc_tag = DeviceValueTAG::TAG_HC1; hc_tag <= DeviceValueTAG::TAG_HC8; hc_tag++) {
|
||||
json = doc.to<JsonObject>();
|
||||
if (emsdevice->generate_values(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json);
|
||||
}
|
||||
}
|
||||
need_publish = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mixer
|
||||
else if (device_type == DeviceType::MIXER) {
|
||||
if (nested) {
|
||||
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
|
||||
} else {
|
||||
for (uint8_t hc_tag = DeviceValueTAG::TAG_HC1; hc_tag <= DeviceValueTAG::TAG_WWC10; hc_tag++) {
|
||||
json = doc.to<JsonObject>();
|
||||
if (emsdevice->generate_values(json, hc_tag, false, EMSdevice::OUTPUT_TARGET::MQTT)) { // not nested
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, hc_tag), json);
|
||||
}
|
||||
}
|
||||
need_publish = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// for all other devices add the values to the json
|
||||
need_publish |= emsdevice->generate_values(json, DeviceValueTAG::TAG_NONE, true, EMSdevice::OUTPUT_TARGET::MQTT); // nested
|
||||
}
|
||||
|
||||
// we want to create the /config topic after the data payload to prevent HA from throwing up a warning
|
||||
if (Mqtt::ha_enabled()) {
|
||||
emsdevice->mqtt_ha_entity_config_create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// publish it under a single topic, only if we have data to publish
|
||||
if (need_publish) {
|
||||
if (doc.overflowed()) {
|
||||
LOG_WARNING(F("MQTT buffer overflow, please use individual topics"));
|
||||
}
|
||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||
snprintf(topic, sizeof(topic), "%s_data", EMSdevice::device_type_2_device_name(device_type).c_str());
|
||||
Mqtt::publish(topic, json);
|
||||
Mqtt::publish(Mqtt::tag_to_topic(device_type, DeviceValueTAG::TAG_NONE), json);
|
||||
}
|
||||
|
||||
// we want to create the /config topic after the data payload to prevent HA from throwing up a warning
|
||||
if (Mqtt::ha_enabled()) {
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||
emsdevice->mqtt_ha_entity_config_create();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,7 +645,6 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
|
||||
std::string src_name("");
|
||||
std::string dest_name("");
|
||||
std::string type_name("");
|
||||
std::string direction("");
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice) {
|
||||
// get src & dest
|
||||
@@ -779,16 +681,15 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
|
||||
type_name = read_flash_string(F("?"));
|
||||
}
|
||||
|
||||
if (telegram->operation == Telegram::Operation::RX_READ) {
|
||||
direction = read_flash_string(F("<-"));
|
||||
} else {
|
||||
direction = read_flash_string(F("->"));
|
||||
}
|
||||
|
||||
std::string str;
|
||||
str.reserve(200);
|
||||
str = src_name + "(" + Helpers::hextoa(src) + ") " + direction + " " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
|
||||
if (telegram->operation == Telegram::Operation::RX_READ) {
|
||||
str = src_name + "(" + Helpers::hextoa(src) + ") <- " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
|
||||
+ Helpers::hextoa(telegram->type_id) + "), length: " + Helpers::hextoa(telegram->message_data[0]);
|
||||
} else {
|
||||
str = src_name + "(" + Helpers::hextoa(src) + ") -> " + dest_name + "(" + Helpers::hextoa(dest) + "), " + type_name + "("
|
||||
+ Helpers::hextoa(telegram->type_id) + "), data: " + telegram->to_string_message();
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
str += " (offset " + Helpers::itoa(offset) + ")";
|
||||
@@ -925,16 +826,13 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
|
||||
// match device_id and type_id
|
||||
// calls the associated process function for that EMS device
|
||||
// returns false if the device_id doesn't recognize it
|
||||
// after the telegram has been processed, call see if there have been values changed and we need to do a MQTT publish
|
||||
// after the telegram has been processed, see if there have been values changed and we need to do a MQTT publish
|
||||
bool found = false;
|
||||
bool knowndevice = false;
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice->is_device_id(telegram->src) || emsdevice->is_device_id(telegram->dest)) {
|
||||
if (emsdevice->is_device_id(telegram->src)) {
|
||||
knowndevice = true;
|
||||
found = emsdevice->handle_telegram(telegram);
|
||||
if (found && emsdevice->is_device_id(telegram->dest)) {
|
||||
LOG_DEBUG(F("Process setting 0x%02X for device 0x%02X"), telegram->type_id, telegram->dest);
|
||||
}
|
||||
// if we correctly processed the telegram then follow up with sending it via MQTT (if enabled)
|
||||
if (found && Mqtt::connected()) {
|
||||
if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->has_update())
|
||||
@@ -951,7 +849,7 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
|
||||
if (wait_validate_ == telegram->type_id) {
|
||||
wait_validate_ = 0;
|
||||
}
|
||||
if (!found && emsdevice->is_device_id(telegram->src) && telegram->message_length > 0) {
|
||||
if (!found && telegram->message_length > 0) {
|
||||
emsdevice->add_handlers_ignored(telegram->type_id);
|
||||
}
|
||||
break;
|
||||
@@ -1007,10 +905,6 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_class.first)) {
|
||||
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
|
||||
if ((num_thermostats > 1) && (emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT)
|
||||
&& (emsdevice->device_id() == actual_master_thermostat())) {
|
||||
shell.printf(F(" **master device**"));
|
||||
}
|
||||
shell.println();
|
||||
emsdevice->show_telegram_handlers(shell);
|
||||
|
||||
@@ -1034,6 +928,9 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
|
||||
// first check to see if we already have it, if so update the record
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && emsdevice->is_device_id(device_id)) {
|
||||
if (product_id == 0) { // update only with valid product_id
|
||||
return true;
|
||||
}
|
||||
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id);
|
||||
emsdevice->product_id(product_id);
|
||||
emsdevice->version(version);
|
||||
@@ -1058,9 +955,9 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
|
||||
for (auto & device : device_library_) {
|
||||
if (device.product_id == product_id) {
|
||||
// sometimes boilers share the same productID as controllers
|
||||
// so only add boilers if the device_id is 0x08, which is fixed for EMS
|
||||
// so only add boilers if the device_id is 0x08 or 0x60 or 0x70.., which is fixed for EMS
|
||||
if (device.device_type == DeviceType::BOILER) {
|
||||
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER
|
||||
if (device_id == EMSdevice::EMS_DEVICE_ID_BOILER || device_id == EMSdevice::EMS_DEVICE_ID_AM200
|
||||
|| (device_id >= EMSdevice::EMS_DEVICE_ID_BOILER_1 && device_id <= EMSdevice::EMS_DEVICE_ID_BOILER_F)) {
|
||||
device_p = &device;
|
||||
break;
|
||||
@@ -1203,23 +1100,36 @@ bool EMSESP::command_commands(uint8_t device_type, JsonObject & output, const in
|
||||
bool EMSESP::command_info(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target) {
|
||||
bool has_value = false;
|
||||
uint8_t tag;
|
||||
if (id >= 1 && id <= 8) {
|
||||
tag = DeviceValueTAG::TAG_HC1 + id - 1;
|
||||
} else if (id >= 9 && id <= 19) {
|
||||
tag = DeviceValueTAG::TAG_WWC1 + id - 9;
|
||||
if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) {
|
||||
tag = DeviceValueTAG::TAG_HC1 + id - 1; // this sets also WWC and HS
|
||||
} else if (id == -1 || id == 0) {
|
||||
tag = DeviceValueTAG::TAG_NONE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id > 0 || output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) {
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)
|
||||
&& ((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat()))) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||
has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0
|
||||
}
|
||||
}
|
||||
|
||||
return has_value;
|
||||
}
|
||||
// for nested output add for each tag
|
||||
for (tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) {
|
||||
JsonObject output_hc = output;
|
||||
bool nest_created = false;
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||
if (!nest_created && emsdevice->has_tag(tag)) {
|
||||
output_hc = output.createNestedObject(EMSdevice::tag_to_string(tag));
|
||||
nest_created = true;
|
||||
}
|
||||
has_value |= emsdevice->generate_values(output_hc, tag, true, output_target); // use nested for id -1 and 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return has_value;
|
||||
}
|
||||
|
||||
@@ -1373,8 +1283,8 @@ void EMSESP::start() {
|
||||
|
||||
// start the file system
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (!LITTLEFS.begin(true)) {
|
||||
Serial.println("LITTLEFS Mount failed. EMS-ESP stopped.");
|
||||
if (!LittleFS.begin(true)) {
|
||||
Serial.println("LittleFS Mount Failed. EMS-ESP stopped.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -134,10 +134,6 @@ class EMSESP {
|
||||
static uint8_t count_devices();
|
||||
static uint8_t device_index(const uint8_t device_type, const uint8_t unique_id);
|
||||
|
||||
static uint8_t actual_master_thermostat();
|
||||
static void actual_master_thermostat(const uint8_t device_id);
|
||||
static uint8_t check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read);
|
||||
|
||||
static bool get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype);
|
||||
|
||||
static void show_device_values(uuid::console::Shell & shell);
|
||||
@@ -261,7 +257,6 @@ class EMSESP {
|
||||
};
|
||||
static std::vector<Device_record> device_library_;
|
||||
|
||||
static uint8_t actual_master_thermostat_;
|
||||
static uint16_t watch_id_;
|
||||
static uint8_t watch_;
|
||||
static uint16_t read_id_;
|
||||
|
||||
@@ -52,7 +52,6 @@ char * Helpers::hextoa(char * result, const uint16_t value) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// same as above but to a hex string
|
||||
std::string Helpers::hextoa(const uint16_t value, bool prefix) {
|
||||
char buf[5];
|
||||
|
||||
@@ -65,8 +65,6 @@ MAKE_PSTR_WORD(reconnect)
|
||||
MAKE_PSTR_WORD(ssid)
|
||||
MAKE_PSTR_WORD(heartbeat)
|
||||
MAKE_PSTR_WORD(users)
|
||||
MAKE_PSTR_WORD(master)
|
||||
MAKE_PSTR_WORD(pin)
|
||||
MAKE_PSTR_WORD(publish)
|
||||
MAKE_PSTR_WORD(timeout)
|
||||
MAKE_PSTR_WORD(board_profile)
|
||||
@@ -105,7 +103,6 @@ MAKE_PSTR_WORD(unknown)
|
||||
MAKE_PSTR_WORD(dallassensor)
|
||||
|
||||
// format strings
|
||||
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat Device ID: %s")
|
||||
MAKE_PSTR(host_fmt, "Host: %s")
|
||||
MAKE_PSTR(port_fmt, "Port: %d")
|
||||
MAKE_PSTR(hostname_fmt, "Hostname: %s")
|
||||
@@ -206,9 +203,9 @@ MAKE_PSTR(l, "l")
|
||||
// mqtt tags must not have spaces
|
||||
MAKE_PSTR(tag_none, "")
|
||||
MAKE_PSTR(tag_heartbeat, "")
|
||||
MAKE_PSTR(tag_boiler_data, "")
|
||||
MAKE_PSTR(tag_device_data_ww, "Warmwasser")
|
||||
MAKE_PSTR(tag_thermostat_data, "")
|
||||
MAKE_PSTR(tag_boiler_data_ww, "ww")
|
||||
MAKE_PSTR(tag_device_data, "")
|
||||
MAKE_PSTR(tag_device_data_ww, "ww")
|
||||
MAKE_PSTR(tag_hc1, "hc1")
|
||||
MAKE_PSTR(tag_hc2, "hc2")
|
||||
MAKE_PSTR(tag_hc3, "hc3")
|
||||
@@ -227,6 +224,7 @@ MAKE_PSTR(tag_wwc7, "wwc7")
|
||||
MAKE_PSTR(tag_wwc8, "wwc8")
|
||||
MAKE_PSTR(tag_wwc9, "wwc9")
|
||||
MAKE_PSTR(tag_wwc10, "wwc10")
|
||||
MAKE_PSTR(tag_ahs, "ahs")
|
||||
MAKE_PSTR(tag_hs1, "hs1")
|
||||
MAKE_PSTR(tag_hs2, "hs2")
|
||||
MAKE_PSTR(tag_hs3, "hs3")
|
||||
@@ -246,8 +244,9 @@ MAKE_PSTR(tag_hs16, "hs16")
|
||||
|
||||
// MQTT topic names
|
||||
// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat")
|
||||
MAKE_PSTR(tag_boiler_data_mqtt, "")
|
||||
MAKE_PSTR(tag_device_data_ww_mqtt, "ww")
|
||||
// MAKE_PSTR(tag_boiler_data_mqtt, "")
|
||||
MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww")
|
||||
MAKE_PSTR(tag_device_data_ww_mqtt, "")
|
||||
|
||||
// boiler
|
||||
MAKE_PSTR(time, "Zeit")
|
||||
@@ -262,6 +261,7 @@ MAKE_PSTR_(continuos, "kontinuierlich")
|
||||
MAKE_PSTR(3wayvalve, "3-Wege Ventil")
|
||||
MAKE_PSTR(chargepump, "Ladepumpe")
|
||||
MAKE_PSTR(hot, "Heiss")
|
||||
MAKE_PSTR(high_comfort, "Heiss Komfort")
|
||||
MAKE_PSTR(eco, "Eco")
|
||||
MAKE_PSTR(intelligent, "Intelligent")
|
||||
MAKE_PSTR_(flow, "Fluss")
|
||||
@@ -270,6 +270,8 @@ MAKE_PSTR_(buffer, "Speicher")
|
||||
MAKE_PSTR(bufferedflow, "Durchlaufspeicher")
|
||||
MAKE_PSTR(layeredbuffer, "Schichtspeicher")
|
||||
MAKE_PSTR(maintenance, "Wartung")
|
||||
MAKE_PSTR(heating, "Heizen")
|
||||
MAKE_PSTR(cooling, "K<EFBFBD>hlen")
|
||||
|
||||
// boiler lists
|
||||
MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) // template for text input
|
||||
@@ -277,10 +279,19 @@ MAKE_PSTR_LIST(enum_off_time_date_manual, F_(off), F_(time), F_(date), F_(manual
|
||||
MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min), F_(5x3min), F_(6x3min), F_(continuous))
|
||||
MAKE_PSTR_LIST(enum_charge, F_(chargepump), F_(3wayvalve))
|
||||
MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent))
|
||||
MAKE_PSTR_LIST(enum_comfort1, F_(high_comfort), F_(eco))
|
||||
MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer))
|
||||
MAKE_PSTR_LIST(enum_reset, F("-"), F_(maintenance), F_(error))
|
||||
// MAKE_PSTR_LIST(enum_bool, F_(off), F_(on))
|
||||
|
||||
// AM200 lists
|
||||
MAKE_PSTR_LIST(enum_vr2Config, F_(off), F("bypass"));
|
||||
MAKE_PSTR_LIST(enum_aPumpSignal, F_(off), F("pwm"), F("pwm_invers"));
|
||||
MAKE_PSTR_LIST(enum_bufBypass, F("no"), F_(mixer), F("valve"));
|
||||
MAKE_PSTR_LIST(enum_bufConfig, F("monovalent"), F("bivalent"));
|
||||
MAKE_PSTR_LIST(enum_blockMode, F_(off), F_(auto), F("blocking"));
|
||||
MAKE_PSTR_LIST(enum_blockTerm, F("n_o"), F("n_c"));
|
||||
|
||||
//heatpump
|
||||
MAKE_PSTR_LIST(enum_hpactivity, F("Kein"), F("Heizen"), F("Kühlen"), F("Warmwasser"), F("Pool"))
|
||||
|
||||
@@ -311,6 +322,7 @@ MAKE_PSTR(winter, "Winter")
|
||||
MAKE_PSTR(outdoor, "Aussentemperatur")
|
||||
MAKE_PSTR_WORD(mpc)
|
||||
MAKE_PSTR(room, "Raum")
|
||||
MAKE_PSTR(room_outdoor, "Raum+Au<41>en")
|
||||
MAKE_PSTR(power, "Leistung")
|
||||
MAKE_PSTR(constant, "konstant")
|
||||
MAKE_PSTR(simple, "einfach")
|
||||
@@ -358,7 +370,7 @@ MAKE_PSTR_LIST(enum_ibaLanguage_RC30, F_(german), F_(dutch))
|
||||
MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end))
|
||||
MAKE_PSTR_LIST(enum_ibaBuildingType, F_(light), F_(medium), F_(heavy)) // RC300
|
||||
MAKE_PSTR_LIST(enum_PID, F("fast"), F_(medium), F("slow"))
|
||||
MAKE_PSTR_LIST(enum_wwMode, F_(off), F_(low), F_(high), F_(auto), F_(own_prog))
|
||||
MAKE_PSTR_LIST(enum_wwMode, F_(off), F("normal"), F_(comfort), F_(auto), F_(own_prog), F_(eco))
|
||||
MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog))
|
||||
MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto))
|
||||
MAKE_PSTR_LIST(enum_wwMode3, F_(on), F_(off), F_(auto))
|
||||
@@ -366,6 +378,7 @@ MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor)
|
||||
MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter))
|
||||
MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F("heizen"), F("kühlen"))
|
||||
MAKE_PSTR_LIST(enum_summer, F_(winter), F_(summer))
|
||||
MAKE_PSTR_LIST(enum_operatingstate, F_(heating), F_(off), F_(cooling))
|
||||
|
||||
MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) // RC100, RC300, RC310
|
||||
MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) // RC20
|
||||
@@ -381,9 +394,12 @@ MAKE_PSTR_LIST(enum_modetype4, F_(nofrost), F_(eco), F_(heat))
|
||||
MAKE_PSTR_LIST(enum_modetype5, F_(off), F_(on))
|
||||
|
||||
MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor))
|
||||
MAKE_PSTR_LIST(enum_reducemode1, F_(outdoor), F_(room), F_(reduce)) // RC310 values: 1-3
|
||||
MAKE_PSTR_LIST(enum_nofrostmode, F_(off), F_(room), F_(outdoor))
|
||||
MAKE_PSTR_LIST(enum_nofrostmode1, F_(room), F_(outdoor), F_(room_outdoor))
|
||||
|
||||
MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant))
|
||||
MAKE_PSTR_LIST(enum_controlmode1, F("weather-compensated"), F("outside-basepoint"), F("n/a"), F_(room)) // RC310 1-4
|
||||
MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room))
|
||||
// MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor"))
|
||||
MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x))
|
||||
@@ -474,6 +490,8 @@ MAKE_PSTR_LIST(maintenanceMessage, F("maintenancemessage"), F("Wartungsmeldung")
|
||||
MAKE_PSTR_LIST(maintenanceDate, F("maintenancedate"), F("Wartungsdatum"))
|
||||
MAKE_PSTR_LIST(maintenanceType, F_(maintenance), F("Wartungsplan"))
|
||||
MAKE_PSTR_LIST(maintenanceTime, F("maintenancetime"), F("Wartung in"))
|
||||
MAKE_PSTR_LIST(emergencyOps, F("emergencyops"), F("emergency operation"))
|
||||
MAKE_PSTR_LIST(emergencyTemp, F("emergencytemp"), F("emergency temperature"))
|
||||
|
||||
// heatpump/compress specific
|
||||
MAKE_PSTR_LIST(upTimeControl, F("uptimecontrol"), F("Betriebszeit total heizen"))
|
||||
@@ -538,6 +556,37 @@ MAKE_PSTR_LIST(electricFactor, F("electricfactor"), F("electric energy factor"))
|
||||
MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support"))
|
||||
MAKE_PSTR_LIST(tempDiffBoiler, F("tempdiffboiler"), F("tempediff boiler support"))
|
||||
|
||||
// alternative heatsource AM200
|
||||
MAKE_PSTR_LIST(aCylTopTemp, F("cyltoptemp"), F("Zylinder oben Temperatur"))
|
||||
MAKE_PSTR_LIST(aCylCenterTemp, F("cylcentertemp"), F("Zylinder mitte Temperatur"))
|
||||
MAKE_PSTR_LIST(aCylBottomTemp, F("cylbottomtemp"), F("Zylinder unten Temperatur"))
|
||||
MAKE_PSTR_LIST(aFlowTemp, F("altflowtemp"), F("Alternativ hs Flusstemperatur"))
|
||||
MAKE_PSTR_LIST(aRetTemp, F("altrettemp"), F("Alternativ hs Rücktemperatur"))
|
||||
MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("System Flusstemperature"))
|
||||
MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("System Rücktemperature"))
|
||||
MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass Ventil"))
|
||||
MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("Puffer Ventil"))
|
||||
MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("Rückfluss Ventil"))
|
||||
MAKE_PSTR_LIST(aPumpMod, F("altpumpmod"), F("Alternativ hs Pumpenmodulation"))
|
||||
MAKE_PSTR_LIST(heatSource, F("heatsource"), F("Alternativ Heizung"))
|
||||
|
||||
MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration"))
|
||||
MAKE_PSTR_LIST(ahsActivated, F("ahsactivated"), F("alternate heat source activation"))
|
||||
MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config"))
|
||||
MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump"))
|
||||
MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1"))
|
||||
MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise"))
|
||||
MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return"))
|
||||
MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time"))
|
||||
// MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temp"))
|
||||
MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config"))
|
||||
MAKE_PSTR_LIST(bufMixRuntime, F("bufmixruntime"), F("bypass mixer run time"))
|
||||
MAKE_PSTR_LIST(bufConfig, F("bufconfig"), F("dhw buffer config"))
|
||||
MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode"))
|
||||
MAKE_PSTR_LIST(blockTerm, F("blockterm"), F("config of block terminal"))
|
||||
MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for bolier block"))
|
||||
MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time"))
|
||||
|
||||
// the following are dhw for the boiler and automatically tagged with 'ww'
|
||||
MAKE_PSTR_LIST(wWSelTemp, F("wwseltemp"), F("gewählte Temperatur"))
|
||||
MAKE_PSTR_LIST(wwSelTempLow, F("wwseltemplow"), F("selected lower temperature"))
|
||||
@@ -565,7 +614,9 @@ MAKE_PSTR_LIST(wWCharging, F("wwcharging"), F("Laden"))
|
||||
MAKE_PSTR_LIST(wWRecharging, F("wwrecharging"), F("Nachladen"))
|
||||
MAKE_PSTR_LIST(wWTempOK, F("wwtempok"), F("Temperatur ok"))
|
||||
MAKE_PSTR_LIST(wWActive, F("wwactive"), F("aktiv"))
|
||||
MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3way valve active"))
|
||||
MAKE_PSTR_LIST(wwTempOK, F("wwtempok"), F("Temperatur ok"))
|
||||
MAKE_PSTR_LIST(wwActive, F("wwactive"), F("aktiv"))
|
||||
MAKE_PSTR_LIST(ww3wayValve, F("ww3wayvalve"), F("3-Wegeventil aktiv"))
|
||||
MAKE_PSTR_LIST(wWSetPumpPower, F("wwsetpumppower"), F("Soll Pumpenleistung"))
|
||||
MAKE_PSTR_LIST(mixerTemp, F("mixertemp"), F("Mischertemperatur"))
|
||||
MAKE_PSTR_LIST(wwCylMiddleTemp, F("wwcylmiddletemp"), F("cylinder middle temperature (TS3)"))
|
||||
@@ -580,11 +631,11 @@ MAKE_PSTR_LIST(wwMaxTemp, F("wwmaxtemp"), F("Maximale Temperatur"))
|
||||
MAKE_PSTR_LIST(wwOneTimeKey, F("wwonetimekey"), F("Einmalladungstaste"))
|
||||
|
||||
// mqtt values / commands
|
||||
MAKE_PSTR_LIST(switchtime, F("switchtime"), F("program switchtime"))
|
||||
MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("own1 program switchtime"))
|
||||
MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("own2 program switchtime"))
|
||||
MAKE_PSTR_LIST(wwswitchtime, F("wwswitchtime"), F("program switchtime"))
|
||||
MAKE_PSTR_LIST(wwcircswitchtime, F("wwcircswitchtime"), F("circulation program switchtime"))
|
||||
MAKE_PSTR_LIST(switchtime, F("switchtime"), F("Program Schaltzeit"))
|
||||
MAKE_PSTR_LIST(switchtime1, F("switchtime1"), F("Program 1 Schaltzeit"))
|
||||
MAKE_PSTR_LIST(switchtime2, F("switchtime2"), F("Programm 2 Schaltzeit"))
|
||||
MAKE_PSTR_LIST(wwswitchtime, F("wwswitchtime"), F("Programm Schaltzeit"))
|
||||
MAKE_PSTR_LIST(wwcircswitchtime, F("wwcircswitchtime"), F("Zirculationsprogramm Schaltzeit"))
|
||||
MAKE_PSTR_LIST(dateTime, F("datetime"), F("Datum/Zeit"))
|
||||
MAKE_PSTR_LIST(errorCode, F("errorcode"), F("Fehlermeldung"))
|
||||
MAKE_PSTR_LIST(ibaMainDisplay, F("display"), F("Anzeige"))
|
||||
@@ -651,8 +702,11 @@ MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("berechnete Flusstemperatu
|
||||
MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("Heizungstyp"))
|
||||
MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("Einstellung Sommerbetrieb"))
|
||||
MAKE_PSTR_LIST(hpoperatingmode, F("hpoperatingmode"), F("Wärmepumpe Betriebsmodus"))
|
||||
MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state"))
|
||||
MAKE_PSTR_LIST(controlmode, F("controlmode"), F("Kontrollmodus"))
|
||||
MAKE_PSTR_LIST(control, F("control"), F("Fernsteuerung"))
|
||||
MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates"))
|
||||
MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates"))
|
||||
MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates"))
|
||||
MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates"))
|
||||
MAKE_PSTR_LIST(program, F("program"), F("Programm"))
|
||||
@@ -669,9 +723,11 @@ MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("Absenkmodus unter Temperatur"))
|
||||
MAKE_PSTR_LIST(vacreducetemp, F("vacreducetemp"), F("Urlaub Absenkmodus unter Temperatur"))
|
||||
MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("Urlaub Absenkmodus"))
|
||||
MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("Frostschutz Modus"))
|
||||
MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode")) // RC310
|
||||
MAKE_PSTR_LIST(remotetemp, F("remotetemp"), F("Raumtemperatur der Fernsteuerung"))
|
||||
MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp"))
|
||||
MAKE_PSTR_LIST(reduceminutes, F("reduceminutes"), F("remaining time for nightmode"))
|
||||
MAKE_PSTR_LIST(switchonoptimization, F("switchonoptimization"), F("switch-on optimization"))
|
||||
|
||||
// heatpump
|
||||
MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative Luftfeuchte"))
|
||||
|
||||
@@ -65,8 +65,6 @@ MAKE_PSTR_WORD(reconnect)
|
||||
MAKE_PSTR_WORD(ssid)
|
||||
MAKE_PSTR_WORD(heartbeat)
|
||||
MAKE_PSTR_WORD(users)
|
||||
MAKE_PSTR_WORD(master)
|
||||
MAKE_PSTR_WORD(pin)
|
||||
MAKE_PSTR_WORD(publish)
|
||||
MAKE_PSTR_WORD(timeout)
|
||||
MAKE_PSTR_WORD(board_profile)
|
||||
@@ -105,7 +103,6 @@ MAKE_PSTR_WORD(unknown)
|
||||
MAKE_PSTR_WORD(dallassensor)
|
||||
|
||||
// format strings
|
||||
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat device ID: %s")
|
||||
MAKE_PSTR(host_fmt, "Host: %s")
|
||||
MAKE_PSTR(port_fmt, "Port: %d")
|
||||
MAKE_PSTR(hostname_fmt, "Hostname: %s")
|
||||
@@ -206,9 +203,9 @@ MAKE_PSTR(l, "l")
|
||||
// mqtt tags must not have spaces
|
||||
MAKE_PSTR(tag_none, "")
|
||||
MAKE_PSTR(tag_heartbeat, "")
|
||||
MAKE_PSTR(tag_boiler_data, "")
|
||||
MAKE_PSTR(tag_boiler_data_ww, "dhw")
|
||||
MAKE_PSTR(tag_device_data, "")
|
||||
MAKE_PSTR(tag_device_data_ww, "dhw")
|
||||
MAKE_PSTR(tag_thermostat_data, "")
|
||||
MAKE_PSTR(tag_hc1, "hc1")
|
||||
MAKE_PSTR(tag_hc2, "hc2")
|
||||
MAKE_PSTR(tag_hc3, "hc3")
|
||||
@@ -227,6 +224,7 @@ MAKE_PSTR(tag_wwc7, "wwc7")
|
||||
MAKE_PSTR(tag_wwc8, "wwc8")
|
||||
MAKE_PSTR(tag_wwc9, "wwc9")
|
||||
MAKE_PSTR(tag_wwc10, "wwc10")
|
||||
MAKE_PSTR(tag_ahs, "ahs")
|
||||
MAKE_PSTR(tag_hs1, "hs1")
|
||||
MAKE_PSTR(tag_hs2, "hs2")
|
||||
MAKE_PSTR(tag_hs3, "hs3")
|
||||
@@ -246,8 +244,9 @@ MAKE_PSTR(tag_hs16, "hs16")
|
||||
|
||||
// MQTT topic names
|
||||
// MAKE_PSTR(tag_heartbeat_mqtt, "heartbeat")
|
||||
MAKE_PSTR(tag_boiler_data_mqtt, "")
|
||||
MAKE_PSTR(tag_device_data_ww_mqtt, "ww")
|
||||
// MAKE_PSTR(tag_boiler_data_mqtt, "")
|
||||
MAKE_PSTR(tag_boiler_data_ww_mqtt, "ww")
|
||||
MAKE_PSTR(tag_device_data_ww_mqtt, "")
|
||||
|
||||
// boiler
|
||||
MAKE_PSTR_WORD(time)
|
||||
@@ -271,6 +270,8 @@ MAKE_PSTR_WORD(buffer)
|
||||
MAKE_PSTR(bufferedflow, "buffered flow")
|
||||
MAKE_PSTR(layeredbuffer, "layered buffer")
|
||||
MAKE_PSTR_WORD(maintenance)
|
||||
MAKE_PSTR_WORD(heating)
|
||||
MAKE_PSTR_WORD(cooling)
|
||||
|
||||
// boiler lists
|
||||
MAKE_PSTR_LIST(tpl_date, F("Format: < dd.mm.yyyy >")) // template for text input
|
||||
@@ -283,8 +284,16 @@ MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(la
|
||||
MAKE_PSTR_LIST(enum_reset, F("-"), F_(maintenance), F_(error))
|
||||
// MAKE_PSTR_LIST(enum_bool, F_(off), F_(on))
|
||||
|
||||
// AM200 lists
|
||||
MAKE_PSTR_LIST(enum_vr2Config, F_(off), F("bypass"));
|
||||
MAKE_PSTR_LIST(enum_aPumpSignal, F_(off), F("pwm"), F("pwm_invers"));
|
||||
MAKE_PSTR_LIST(enum_bufBypass, F("no"), F_(mixer), F("valve"));
|
||||
MAKE_PSTR_LIST(enum_bufConfig, F("monovalent"), F("bivalent"));
|
||||
MAKE_PSTR_LIST(enum_blockMode, F_(off), F_(auto), F("blocking"));
|
||||
MAKE_PSTR_LIST(enum_blockTerm, F("n_o"), F("n_c"));
|
||||
|
||||
//heatpump
|
||||
MAKE_PSTR_LIST(enum_hpactivity, F("none"), F("heating"), F("cooling"), F("hot water"), F("pool"))
|
||||
MAKE_PSTR_LIST(enum_hpactivity, F("none"), F_(heating), F_(cooling), F("hot_water"), F("pool"))
|
||||
|
||||
// mixer
|
||||
MAKE_PSTR_LIST(enum_shunt, F("stopped"), F("opening"), F("closing"), F("open"), F("close"))
|
||||
@@ -313,6 +322,7 @@ MAKE_PSTR_WORD(winter)
|
||||
MAKE_PSTR_WORD(outdoor)
|
||||
MAKE_PSTR_WORD(mpc)
|
||||
MAKE_PSTR_WORD(room)
|
||||
MAKE_PSTR_WORD(room_outdoor)
|
||||
MAKE_PSTR_WORD(power)
|
||||
MAKE_PSTR_WORD(constant)
|
||||
MAKE_PSTR_WORD(simple)
|
||||
@@ -341,7 +351,7 @@ MAKE_PSTR(functioning_mode, "functioning mode")
|
||||
MAKE_PSTR(smoke_temperature, "smoke temperature")
|
||||
|
||||
// thermostat lists
|
||||
MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-dw-dst >"))
|
||||
MAKE_PSTR_LIST(tpl_datetime, F("Format: < NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1) >"))
|
||||
MAKE_PSTR_LIST(tpl_switchtime, F("Format: <nn> [ not_set | day hh:mm on|off ]"))
|
||||
MAKE_PSTR_LIST(tpl_switchtime1, F("Format: <nn> [ not_set | day hh:mm Tn ]"))
|
||||
MAKE_PSTR_LIST(tpl_holidays, F("format: < dd.mm.yyyy-dd.mm.yyyy >"))
|
||||
@@ -360,14 +370,15 @@ MAKE_PSTR_LIST(enum_ibaLanguage_RC30, F_(german), F_(dutch))
|
||||
MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end))
|
||||
MAKE_PSTR_LIST(enum_ibaBuildingType, F_(light), F_(medium), F_(heavy))
|
||||
MAKE_PSTR_LIST(enum_PID, F("fast"), F_(medium), F("slow"))
|
||||
MAKE_PSTR_LIST(enum_wwMode, F_(off), F_(low), F_(high), F_(auto), F_(own_prog))
|
||||
MAKE_PSTR_LIST(enum_wwMode, F_(off), F("normal"), F_(comfort), F_(auto), F_(own_prog), F_(eco))
|
||||
MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog))
|
||||
MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto))
|
||||
MAKE_PSTR_LIST(enum_wwMode3, F_(on), F_(off), F_(auto))
|
||||
MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor))
|
||||
MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter))
|
||||
MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F("heating"), F("cooling"))
|
||||
MAKE_PSTR_LIST(enum_hpoperatingmode, F_(off), F_(auto), F_(heating), F_(cooling))
|
||||
MAKE_PSTR_LIST(enum_summer, F_(winter), F_(summer))
|
||||
MAKE_PSTR_LIST(enum_operatingstate, F_(heating), F_(off), F_(cooling))
|
||||
|
||||
MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) // RC100, RC300, RC310
|
||||
MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) // RC20
|
||||
@@ -383,9 +394,12 @@ MAKE_PSTR_LIST(enum_modetype4, F_(nofrost), F_(eco), F_(heat))
|
||||
MAKE_PSTR_LIST(enum_modetype5, F_(off), F_(on))
|
||||
|
||||
MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor))
|
||||
MAKE_PSTR_LIST(enum_reducemode1, F_(outdoor), F_(room), F_(reduce)) // RC310 values: 1-3
|
||||
MAKE_PSTR_LIST(enum_nofrostmode, F_(off), F_(room), F_(outdoor))
|
||||
MAKE_PSTR_LIST(enum_nofrostmode1, F_(room), F_(outdoor), F_(room_outdoor))
|
||||
|
||||
MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(optimized), F_(simple), F_(mpc), F_(room), F_(power), F_(constant))
|
||||
MAKE_PSTR_LIST(enum_controlmode1, F("weather-compensated"), F("outside-basepoint"), F("n/a"), F_(room)) // RC310 1-4
|
||||
MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room))
|
||||
// MAKE_PSTR_LIST(enum_controlmode3, F_(off), F_(room), F_(outdoor), F("room+outdoor"))
|
||||
MAKE_PSTR_LIST(enum_control, F_(off), F_(rc20), F_(rc3x))
|
||||
@@ -531,6 +545,37 @@ MAKE_PSTR_LIST(electricFactor, F("electricfactor"), F("electric energy factor"))
|
||||
MAKE_PSTR_LIST(delayBoiler, F("delayboiler"), F("delay boiler support"))
|
||||
MAKE_PSTR_LIST(tempDiffBoiler, F("tempdiffboiler"), F("tempediff boiler support"))
|
||||
|
||||
// alternative heatsource AM200
|
||||
MAKE_PSTR_LIST(aCylTopTemp, F("cyltoptemp"), F("cylinder top temperature"))
|
||||
MAKE_PSTR_LIST(aCylCenterTemp, F("cylcentertemp"), F("cylinder center temperature"))
|
||||
MAKE_PSTR_LIST(aCylBottomTemp, F("cylbottomtemp"), F("cylinder bottom temperature"))
|
||||
MAKE_PSTR_LIST(aFlowTemp, F("altflowtemp"), F("alternative hs flow temperature"))
|
||||
MAKE_PSTR_LIST(aRetTemp, F("altrettemp"), F("alternative hs return temperature"))
|
||||
MAKE_PSTR_LIST(sysFlowTemp, F("sysflowtemp"), F("system flow temperature"))
|
||||
MAKE_PSTR_LIST(sysRetTemp, F("sysrettemp"), F("system return temperature"))
|
||||
MAKE_PSTR_LIST(valveByPass, F("valvebypass"), F("bypass valve"))
|
||||
MAKE_PSTR_LIST(valveBuffer, F("valvebuffer"), F("buffer valve"))
|
||||
MAKE_PSTR_LIST(valveReturn, F("valvereturn"), F("return valve"))
|
||||
MAKE_PSTR_LIST(aPumpMod, F("altpumpmod"), F("alternative hs pump modulation"))
|
||||
MAKE_PSTR_LIST(heatSource, F("heatsource"), F("alternative heating active"))
|
||||
|
||||
MAKE_PSTR_LIST(vr2Config, F("vr2config"), F("vr2 configuration"))
|
||||
MAKE_PSTR_LIST(ahsActivated, F("ahsactivated"), F("alternate heat source activation"))
|
||||
MAKE_PSTR_LIST(aPumpConfig, F("apumpconfig"), F("primary pump config"))
|
||||
MAKE_PSTR_LIST(aPumpSignal, F("apumpsignal"), F("output for pr1 pump"))
|
||||
MAKE_PSTR_LIST(aPumpMin, F("apumpmin"), F("min output pump pr1"))
|
||||
MAKE_PSTR_LIST(tempRise, F("temprise"), F("ahs return temp rise"))
|
||||
MAKE_PSTR_LIST(setReturnTemp, F("setreturntemp"), F("set temp return"))
|
||||
MAKE_PSTR_LIST(mixRuntime, F("mixruntime"), F("mixer run time"))
|
||||
// MAKE_PSTR_LIST(setFlowTemp, F("setflowtemp"), F("set flow temp"))
|
||||
MAKE_PSTR_LIST(bufBypass, F("bufbypass"), F("buffer bypass config"))
|
||||
MAKE_PSTR_LIST(bufMixRuntime, F("bufmixruntime"), F("bypass mixer run time"))
|
||||
MAKE_PSTR_LIST(bufConfig, F("bufconfig"), F("dhw buffer config"))
|
||||
MAKE_PSTR_LIST(blockMode, F("blockmode"), F("config htg. blocking mode"))
|
||||
MAKE_PSTR_LIST(blockTerm, F("blockterm"), F("config of block terminal"))
|
||||
MAKE_PSTR_LIST(blockHyst, F("blockhyst"), F("hyst. for bolier block"))
|
||||
MAKE_PSTR_LIST(releaseWait, F("releasewait"), F("boiler release wait time"))
|
||||
|
||||
// the following are dhw for the boiler and automatically tagged with 'ww'
|
||||
MAKE_PSTR_LIST(wwSelTemp, F("wwseltemp"), F("selected temperature"))
|
||||
MAKE_PSTR_LIST(wwSelTempLow, F("wwseltemplow"), F("selected lower temperature"))
|
||||
@@ -632,6 +677,7 @@ MAKE_PSTR_LIST(nighttemp2, F("nighttemp"), F("night temperature T1"))
|
||||
MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco temperature"))
|
||||
MAKE_PSTR_LIST(manualtemp, F("manualtemp"), F("manual temperature"))
|
||||
MAKE_PSTR_LIST(tempautotemp, F("tempautotemp"), F("temporary set temperature automode"))
|
||||
MAKE_PSTR_LIST(remoteseltemp, F("remoteseltemp"), F("temporary set temperature from remote"))
|
||||
MAKE_PSTR_LIST(comforttemp, F("comforttemp"), F("comfort temperature"))
|
||||
MAKE_PSTR_LIST(summertemp, F("summertemp"), F("summer temperature"))
|
||||
MAKE_PSTR_LIST(designtemp, F("designtemp"), F("design temperature"))
|
||||
@@ -646,8 +692,11 @@ MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("target flow temperature")
|
||||
MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("heating type"))
|
||||
MAKE_PSTR_LIST(summersetmode, F("summersetmode"), F("set summer mode"))
|
||||
MAKE_PSTR_LIST(hpoperatingmode, F("hpoperatingmode"), F("heatpump operating mode"))
|
||||
MAKE_PSTR_LIST(hpoperatingstate, F("hpoperatingstate"), F("heatpump operating state"))
|
||||
MAKE_PSTR_LIST(controlmode, F("controlmode"), F("control mode"))
|
||||
MAKE_PSTR_LIST(control, F("control"), F("control device"))
|
||||
MAKE_PSTR_LIST(wwHolidays, F("wwholidays"), F("holiday dates"))
|
||||
MAKE_PSTR_LIST(wwVacations, F("wwvacations"), F("vacation dates"))
|
||||
MAKE_PSTR_LIST(holidays, F("holidays"), F("holiday dates"))
|
||||
MAKE_PSTR_LIST(vacations, F("vacations"), F("vacation dates"))
|
||||
MAKE_PSTR_LIST(program, F("program"), F("program"))
|
||||
@@ -664,9 +713,11 @@ MAKE_PSTR_LIST(reducetemp, F("reducetemp"), F("off/reduce switch temperature"))
|
||||
MAKE_PSTR_LIST(vacreducetemp, F("vacreducetemp"), F("vacations off/reduce switch temperature"))
|
||||
MAKE_PSTR_LIST(vacreducemode, F("vacreducemode"), F("vacations reduce mode"))
|
||||
MAKE_PSTR_LIST(nofrostmode, F("nofrostmode"), F("nofrost mode"))
|
||||
MAKE_PSTR_LIST(nofrostmode1, F("nofrostmode1"), F("nofrost mode")) // RC310
|
||||
MAKE_PSTR_LIST(remotetemp, F("remotetemp"), F("room temperature from remote"))
|
||||
MAKE_PSTR_LIST(reducehours, F("reducehours"), F("duration for nighttemp"))
|
||||
MAKE_PSTR_LIST(reduceminutes, F("reduceminutes"), F("remaining time for nightmode"))
|
||||
MAKE_PSTR_LIST(switchonoptimization, F("switchonoptimization"), F("switch-on optimization"))
|
||||
|
||||
// heatpump
|
||||
MAKE_PSTR_LIST(airHumidity, F("airhumidity"), F("relative air humidity"))
|
||||
|
||||
55
src/mqtt.cpp
55
src/mqtt.cpp
@@ -445,19 +445,17 @@ void Mqtt::start() {
|
||||
}
|
||||
connecting_ = false;
|
||||
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
|
||||
LOG_INFO(F("MQTT disconnected: TCP"));
|
||||
}
|
||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
|
||||
LOG_INFO(F("MQTT disconnected: Identifier Rejected"));
|
||||
}
|
||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
|
||||
LOG_INFO(F("MQTT disconnected: Server unavailable"));
|
||||
}
|
||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
|
||||
LOG_INFO(F("MQTT disconnected: Malformed credentials"));
|
||||
}
|
||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
|
||||
LOG_INFO(F("MQTT disconnected: Not authorized"));
|
||||
LOG_WARNING(F("MQTT disconnected: TCP"));
|
||||
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
|
||||
LOG_WARNING(F("MQTT disconnected: Identifier Rejected"));
|
||||
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
|
||||
LOG_WARNING(F("MQTT disconnected: Server unavailable"));
|
||||
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
|
||||
LOG_WARNING(F("MQTT disconnected: Malformed credentials"));
|
||||
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
|
||||
LOG_WARNING(F("MQTT disconnected: Not authorized"));
|
||||
} else {
|
||||
LOG_WARNING(F("MQTT disconnected: code %d"), reason);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -629,6 +627,7 @@ void Mqtt::ha_status() {
|
||||
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
|
||||
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes
|
||||
doc["stat_t"] = FJSON("~/heartbeat");
|
||||
doc["object_id"] = FJSON("ems_esp_status");
|
||||
doc["name"] = FJSON("EMS-ESP status");
|
||||
doc["ic"] = F_(icondevice);
|
||||
doc["val_tpl"] = FJSON("{{value_json['bus_status']}}");
|
||||
@@ -1104,15 +1103,23 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
|
||||
snprintf(stat_t, sizeof(stat_t), "~/%s", tag_to_topic(device_type, tag).c_str());
|
||||
doc["stat_t"] = stat_t;
|
||||
|
||||
// name = <device> <tag> <name>
|
||||
char new_name[80];
|
||||
// friendly name = <tag> <name>
|
||||
char short_name[70];
|
||||
if (have_tag) {
|
||||
snprintf(new_name, sizeof(new_name), "%s %s %s", device_name, EMSdevice::tag_to_string(tag).c_str(), read_flash_string(name).c_str());
|
||||
snprintf(short_name, sizeof(short_name), "%s %s", EMSdevice::tag_to_string(tag).c_str(), read_flash_string(name).c_str());
|
||||
} else {
|
||||
snprintf(new_name, sizeof(new_name), "%s %s", device_name, read_flash_string(name).c_str());
|
||||
snprintf(short_name, sizeof(short_name), "%s", read_flash_string(name).c_str());
|
||||
}
|
||||
new_name[0] = toupper(new_name[0]); // capitalize first letter
|
||||
doc["name"] = new_name;
|
||||
|
||||
// entity id = emsesp_<device>_<tag>_<name>
|
||||
char long_name[130];
|
||||
snprintf(long_name, sizeof(long_name), "%s_%s", device_name, short_name);
|
||||
// snprintf(long_name, sizeof(long_name), "emsesp_%s_%s", device_name, short_name); //wouldn't it be better?
|
||||
doc["object_id"] = long_name;
|
||||
|
||||
// name (friendly name) = <tag> <name>
|
||||
short_name[0] = toupper(short_name[0]); // capitalize first letter
|
||||
doc["name"] = short_name;
|
||||
|
||||
// value template
|
||||
// if its nested mqtt format then use the appended entity name, otherwise take the original
|
||||
@@ -1240,7 +1247,8 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
|
||||
char seltemp_s[30];
|
||||
char currtemp_s[30];
|
||||
char mode_str_tpl[400];
|
||||
char name_s[30];
|
||||
char name_s[10];
|
||||
char id_s[20];
|
||||
char uniq_id_s[30];
|
||||
char temp_cmd_s[30];
|
||||
char mode_cmd_s[30];
|
||||
@@ -1279,7 +1287,8 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
|
||||
hc_mode_s,
|
||||
hc_mode_s);
|
||||
|
||||
snprintf(name_s, sizeof(name_s), "Thermostat hc%d", hc_num);
|
||||
snprintf(id_s, sizeof(id_s), "thermostat_hc%d", hc_num);
|
||||
snprintf(name_s, sizeof(name_s), "Hc%d", hc_num);
|
||||
snprintf(uniq_id_s, sizeof(uniq_id_s), "thermostat_hc%d", hc_num);
|
||||
snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num);
|
||||
snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
|
||||
@@ -1287,6 +1296,7 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
||||
|
||||
doc["~"] = base();
|
||||
doc["object_id"] = id_s;
|
||||
doc["name"] = name_s;
|
||||
doc["uniq_id"] = uniq_id_s;
|
||||
doc["mode_stat_t"] = topic_t;
|
||||
@@ -1329,8 +1339,7 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, uint8_t tag) {
|
||||
}
|
||||
|
||||
// if there is a tag add it
|
||||
if (!EMSdevice::tag_to_mqtt(tag).empty()
|
||||
&& ((device_type == EMSdevice::DeviceType::BOILER && tag == DeviceValueTAG::TAG_DEVICE_DATA_WW) || (!is_nested() && tag >= DeviceValueTAG::TAG_HC1))) {
|
||||
if (!EMSdevice::tag_to_mqtt(tag).empty() && ((tag == DeviceValueTAG::TAG_BOILER_DATA_WW) || (!is_nested() && tag >= DeviceValueTAG::TAG_HC1))) {
|
||||
return EMSdevice::device_type_2_device_name(device_type) + "_data_" + EMSdevice::tag_to_mqtt(tag);
|
||||
} else {
|
||||
return EMSdevice::device_type_2_device_name(device_type) + "_data";
|
||||
|
||||
@@ -57,7 +57,6 @@ void Shower::loop() {
|
||||
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath
|
||||
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
|
||||
set_shower_state(true);
|
||||
publish_shower_data();
|
||||
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
|
||||
}
|
||||
// check if the shower has been on too long
|
||||
@@ -78,7 +77,12 @@ void Shower::loop() {
|
||||
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
|
||||
duration_ = (timer_pause_ - timer_start_ - SHOWER_OFFSET_TIME);
|
||||
if (duration_ > SHOWER_MIN_DURATION) {
|
||||
publish_shower_data();
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||
|
||||
char s[50];
|
||||
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
|
||||
doc["duration"] = s;
|
||||
Mqtt::publish(F("shower_data"), doc.as<JsonObject>());
|
||||
LOG_DEBUG(F("[Shower] finished with duration %d"), duration_);
|
||||
}
|
||||
}
|
||||
@@ -120,34 +124,6 @@ void Shower::shower_alert_start() {
|
||||
}
|
||||
}
|
||||
|
||||
// Publish to the shower_data topic
|
||||
// showing whether the shower timer and alert are enabled or disabled
|
||||
// and the duration of the last shower
|
||||
void Shower::publish_shower_data() const {
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||
|
||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||
doc["shower_timer"] = shower_timer_;
|
||||
doc["shower_alert"] = shower_alert_;
|
||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||
doc["shower_timer"] = shower_timer_ ? 1 : 0;
|
||||
doc["shower_alert"] = shower_alert_ ? 1 : 0;
|
||||
} else {
|
||||
char result[10];
|
||||
doc["shower_timer"] = Helpers::render_boolean(result, shower_timer_);
|
||||
doc["shower_alert"] = Helpers::render_boolean(result, shower_alert_);
|
||||
}
|
||||
|
||||
// only publish shower duration if there is a value
|
||||
if (duration_ > SHOWER_MIN_DURATION) {
|
||||
char s[50];
|
||||
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
|
||||
doc["duration"] = s;
|
||||
}
|
||||
|
||||
Mqtt::publish(F("shower_data"), doc.as<JsonObject>());
|
||||
}
|
||||
|
||||
// send status of shower to MQTT topic called shower_active - which is determined by the state parameter
|
||||
// and creates the HA config topic if HA enabled
|
||||
// force is used by EMSESP::publish_all_loop()
|
||||
|
||||
20
src/shower.h
20
src/shower.h
@@ -30,25 +30,6 @@ class Shower {
|
||||
|
||||
void set_shower_state(bool state, bool force = false);
|
||||
|
||||
/* unused header
|
||||
*
|
||||
bool shower_alert() const {
|
||||
return shower_alert_;
|
||||
}
|
||||
|
||||
void shower_alert(const bool shower_alert) {
|
||||
shower_alert_ = shower_alert;
|
||||
}
|
||||
|
||||
bool shower_timer() const {
|
||||
return shower_timer_;
|
||||
}
|
||||
|
||||
void shower_timer(const bool shower_timer) {
|
||||
shower_timer_ = shower_timer;
|
||||
}
|
||||
*/
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
@@ -56,7 +37,6 @@ class Shower {
|
||||
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
|
||||
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
||||
|
||||
void publish_shower_data() const;
|
||||
void shower_alert_start();
|
||||
void shower_alert_stop();
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ void System::format(uuid::console::Shell & shell) {
|
||||
EMSuart::stop();
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
LITTLEFS.format();
|
||||
LittleFS.format();
|
||||
#endif
|
||||
|
||||
System::system_restart();
|
||||
@@ -433,7 +433,7 @@ void System::button_OnVLongPress(PButton & b) {
|
||||
EMSESP::console_.loop();
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
Test::listDir(LITTLEFS, FS_CONFIG_DIRECTORY, 3);
|
||||
Test::listDir(LittleFS, FS_CONFIG_DIRECTORY, 3);
|
||||
#endif
|
||||
|
||||
EMSESP::esp8266React.factoryReset();
|
||||
@@ -895,7 +895,7 @@ bool System::check_upgrade() {
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// see if we have a temp file, if so try and read it
|
||||
File new_file = LITTLEFS.open(TEMP_FILENAME_PATH);
|
||||
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
|
||||
if (new_file) {
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(FS_BUFFER_SIZE);
|
||||
DeserializationError error = deserializeJson(jsonDocument, new_file);
|
||||
@@ -923,7 +923,7 @@ bool System::check_upgrade() {
|
||||
|
||||
// close (just in case) and remove the temp file
|
||||
new_file.close();
|
||||
LITTLEFS.remove(TEMP_FILENAME_PATH);
|
||||
LittleFS.remove(TEMP_FILENAME_PATH);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -938,9 +938,9 @@ bool System::command_commands(const char * value, const int8_t id, JsonObject &
|
||||
// convert settings file into json object
|
||||
void System::extractSettings(const char * filename, const char * section, JsonObject & output) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
File settingsFile = LITTLEFS.open(filename);
|
||||
File settingsFile = LittleFS.open(filename);
|
||||
if (settingsFile) {
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(FS_BUFFER_SIZE);
|
||||
DeserializationError error = deserializeJson(jsonDocument, settingsFile);
|
||||
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
|
||||
JsonObject jsonObject = jsonDocument.as<JsonObject>();
|
||||
@@ -959,7 +959,7 @@ bool System::saveSettings(const char * filename, const char * section, JsonObjec
|
||||
#ifndef EMSESP_STANDALONE
|
||||
JsonObject section_json = input[section];
|
||||
if (section_json) {
|
||||
File section_file = LITTLEFS.open(filename, "w");
|
||||
File section_file = LittleFS.open(filename, "w");
|
||||
if (section_file) {
|
||||
LOG_INFO(F("Applying new %s settings"), section);
|
||||
serializeJson(section_json, section_file);
|
||||
|
||||
14
src/system.h
14
src/system.h
@@ -77,6 +77,20 @@ class System {
|
||||
bool heartbeat_json(JsonObject & output);
|
||||
void send_heartbeat();
|
||||
|
||||
bool syslog_enabled() {
|
||||
return syslog_enabled_;
|
||||
}
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
unsigned long syslog_count() {
|
||||
return syslog_.message_count();
|
||||
}
|
||||
|
||||
unsigned long syslog_fails() {
|
||||
return syslog_.message_fails();
|
||||
}
|
||||
#endif
|
||||
|
||||
void led_init(bool refresh);
|
||||
void network_init(bool refresh);
|
||||
void button_init(bool refresh);
|
||||
|
||||
@@ -221,9 +221,6 @@ void RxService::add(uint8_t * data, uint8_t length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we receive a hc2.. telegram from 0x19.. match it to master_thermostat if master is 0x18
|
||||
src = EMSESP::check_master_device(src, type_id, true);
|
||||
|
||||
// create the telegram
|
||||
auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length);
|
||||
|
||||
@@ -236,8 +233,8 @@ void RxService::add(uint8_t * data, uint8_t length) {
|
||||
}
|
||||
|
||||
// add empty telegram to rx-queue
|
||||
void RxService::add_empty(const uint8_t src, const uint8_t dest, const uint16_t type_id) {
|
||||
auto telegram = std::make_shared<Telegram>(Telegram::Operation::RX, src, dest, type_id, 0, nullptr, 0);
|
||||
void RxService::add_empty(const uint8_t src, const uint8_t dest, const uint16_t type_id, uint8_t offset) {
|
||||
auto telegram = std::make_shared<Telegram>(Telegram::Operation::RX, src, dest, type_id, offset, nullptr, 0);
|
||||
// only if queue is not full
|
||||
if (rx_telegrams_.size() < MAX_RX_TELEGRAMS) {
|
||||
rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue
|
||||
@@ -312,9 +309,6 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
|
||||
// fix the READ or WRITE depending on the operation
|
||||
uint8_t dest = telegram->dest;
|
||||
|
||||
// check if we have to manipulate the id for thermostats > 0x18
|
||||
dest = EMSESP::check_master_device(dest, telegram->type_id, false);
|
||||
|
||||
if (telegram->operation == Telegram::Operation::TX_READ) {
|
||||
dest |= 0x80; // read has 8th bit set for the destination
|
||||
}
|
||||
@@ -592,19 +586,22 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
|
||||
// have we reached the limit? if so, reset count and give up
|
||||
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
|
||||
reset_retry_count(); // give up
|
||||
EMSESP::wait_validate(0); // do not wait for validation
|
||||
if (operation == Telegram::Operation::TX_READ) {
|
||||
if (telegram_last_->offset > 0) { // ignore errors for higher offsets
|
||||
LOG_DEBUG(F("Last Tx Read operation failed after %d retries. Ignoring request: %s"), MAXIMUM_TX_RETRIES, telegram_last_->to_string().c_str());
|
||||
return;
|
||||
}
|
||||
increment_telegram_read_fail_count(); // another Tx fail
|
||||
} else {
|
||||
increment_telegram_write_fail_count(); // another Tx fail
|
||||
}
|
||||
EMSESP::wait_validate(0); // do not wait for validation
|
||||
|
||||
LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request: %s"),
|
||||
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
|
||||
MAXIMUM_TX_RETRIES,
|
||||
telegram_last_->to_string().c_str());
|
||||
if (operation == Telegram::Operation::TX_READ) {
|
||||
EMSESP::rxservice_.add_empty(telegram_last_->dest, telegram_last_->src, telegram_last_->type_id);
|
||||
EMSESP::rxservice_.add_empty(telegram_last_->dest, telegram_last_->src, telegram_last_->type_id, telegram_last_->offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ class RxService : public EMSbus {
|
||||
|
||||
void loop();
|
||||
void add(uint8_t * data, uint8_t length);
|
||||
void add_empty(const uint8_t src, const uint8_t dst, const uint16_t type_id);
|
||||
void add_empty(const uint8_t src, const uint8_t dst, const uint16_t type_id, uint8_t offset);
|
||||
|
||||
uint32_t telegram_count() const {
|
||||
return telegram_count_;
|
||||
|
||||
@@ -692,6 +692,27 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
EMSESP::mqtt_.incoming("ems-esp/boiler/wwseltemp", "59");
|
||||
}
|
||||
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
// https://github.com/emsesp/EMS-ESP32/issues/541
|
||||
if (command == "api_wwmode") {
|
||||
shell.printfln(F("Testing API wwmode"));
|
||||
Mqtt::ha_enabled(false);
|
||||
Mqtt::nested_format(1);
|
||||
run_test("310");
|
||||
|
||||
AsyncWebServerRequest request;
|
||||
request.method(HTTP_POST);
|
||||
DynamicJsonDocument doc(2000);
|
||||
JsonVariant json;
|
||||
|
||||
char data[] = "{\"value\":\"off\"}";
|
||||
deserializeJson(doc, data);
|
||||
json = doc.as<JsonVariant>();
|
||||
request.url("/api/thermostat/wwmode");
|
||||
EMSESP::webAPIService.webAPIService_post(&request, json);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (command == "api") {
|
||||
shell.printfln(F("Testing API with MQTT and REST, standalone"));
|
||||
|
||||
@@ -1638,7 +1659,7 @@ void Test::debug(uuid::console::Shell & shell, const std::string & cmd) {
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (command == "ls") {
|
||||
listDir(LITTLEFS, "/", 3);
|
||||
listDir(LittleFS, "/", 3);
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace emsesp {
|
||||
// #define EMSESP_DEBUG_DEFAULT "web"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt"
|
||||
// #define EMSESP_DEBUG_DEFAULT "general"
|
||||
// #define EMSESP_DEBUG_DEFAULT "boiler"
|
||||
#define EMSESP_DEBUG_DEFAULT "boiler"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt2"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
|
||||
// #define EMSESP_DEBUG_DEFAULT "ha"
|
||||
@@ -48,8 +48,9 @@ namespace emsesp {
|
||||
// #define EMSESP_DEBUG_DEFAULT "2thermostats"
|
||||
// #define EMSESP_DEBUG_DEFAULT "dallas"
|
||||
// #define EMSESP_DEBUG_DEFAULT "analog"
|
||||
#define EMSESP_DEBUG_DEFAULT "api_values"
|
||||
// #define EMSESP_DEBUG_DEFAULT "api_values"
|
||||
// #define EMSESP_DEBUG_DEFAULT "mqtt_post"
|
||||
// #define EMSESP_DEBUG_DEFAULT "api_wwmode"
|
||||
|
||||
class Test {
|
||||
public:
|
||||
|
||||
@@ -20,127 +20,87 @@
|
||||
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380
|
||||
*/
|
||||
|
||||
#if defined(ESP32)
|
||||
#ifndef EMSESP_STANDALONE
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "uart/emsuart_esp32.h"
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
RingbufHandle_t buf_handle_ = NULL;
|
||||
portMUX_TYPE mux_ = portMUX_INITIALIZER_UNLOCKED;
|
||||
bool drop_next_rx_ = true;
|
||||
static QueueHandle_t uart_queue;
|
||||
uint8_t tx_mode_ = 0xFF;
|
||||
|
||||
/*
|
||||
* Task to handle the incoming data
|
||||
* receive task, wait for break and call incoming_telegram
|
||||
*/
|
||||
void EMSuart::emsuart_recvTask(void * para) {
|
||||
while (1) {
|
||||
size_t item_size;
|
||||
uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle_, &item_size, portMAX_DELAY);
|
||||
uint8_t telegramSize = item_size;
|
||||
if (telegram) {
|
||||
EMSESP::incoming_telegram(telegram, telegramSize);
|
||||
vRingbufferReturnItem(buf_handle_, (void *)telegram);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* UART interrupt, on break read the fifo and put the whole telegram to ringbuffer
|
||||
*/
|
||||
void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
|
||||
portENTER_CRITICAL(&mux_);
|
||||
if (EMS_UART.int_st.brk_det) {
|
||||
EMS_UART.int_clr.brk_det = 1; // clear flag
|
||||
uint8_t rxbuf[EMS_MAXBUFFERSIZE];
|
||||
void EMSuart::uart_event_task(void * pvParameters) {
|
||||
uart_event_t event;
|
||||
uint8_t telegram[EMS_MAXBUFFERSIZE];
|
||||
uint8_t length = 0;
|
||||
while (EMS_UART.status.rxfifo_cnt) {
|
||||
uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes from fifo
|
||||
if (length < EMS_MAXBUFFERSIZE) {
|
||||
if (length || rx) { // skip leading zero
|
||||
rxbuf[length++] = rx;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
//Waiting for UART event.
|
||||
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY)) {
|
||||
if (event.type == UART_DATA) {
|
||||
length += event.size;
|
||||
} else if (event.type == UART_BREAK) {
|
||||
if (length == 2 || (length >= 6 && length <= EMS_MAXBUFFERSIZE)) {
|
||||
uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
|
||||
// if (telegram[0] && !telegram[length - 1]) {
|
||||
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
|
||||
// }
|
||||
} else {
|
||||
drop_next_rx_ = true; // we have a overflow
|
||||
// flush buffer up to break
|
||||
uint8_t buf[length];
|
||||
uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
|
||||
}
|
||||
length = 0;
|
||||
} else if (event.type == UART_BUFFER_FULL) {
|
||||
uart_flush_input(EMSUART_NUM);
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
if (length > 0 && length < EMS_MAXBUFFERSIZE) {
|
||||
if (rxbuf[length - 1]) { // check if last byte is break
|
||||
length++;
|
||||
}
|
||||
}
|
||||
if ((!drop_next_rx_) && ((length == 2) || (length > 4))) {
|
||||
int baseType = 0;
|
||||
xRingbufferSendFromISR(buf_handle_, rxbuf, length - 1, &baseType);
|
||||
}
|
||||
drop_next_rx_ = false;
|
||||
}
|
||||
portEXIT_CRITICAL(&mux_);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* init UART driver
|
||||
*/
|
||||
void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) {
|
||||
if (tx_mode_ != 0xFF) { // uart already initialized
|
||||
tx_mode_ = tx_mode;
|
||||
restart();
|
||||
return;
|
||||
}
|
||||
tx_mode_ = tx_mode;
|
||||
portENTER_CRITICAL(&mux_);
|
||||
if (tx_mode_ == 0xFF) {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = EMSUART_BAUD,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
|
||||
uart_param_config(EMSUART_UART, &uart_config);
|
||||
uart_set_pin(EMSUART_UART, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
EMS_UART.int_ena.val = 0; // disable all intr.
|
||||
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
|
||||
EMS_UART.idle_conf.tx_brk_num = 10; // breaklength 10 bit
|
||||
drop_next_rx_ = true;
|
||||
// EMS_UART.idle_conf.rx_idle_thrhd = 256;
|
||||
// EMS_UART.auto_baud.glitch_filt = 192;
|
||||
#if (EMSUART_UART != UART_NUM_2)
|
||||
EMS_UART.conf0.rxfifo_rst = 1; // flush fifos, remove for UART2
|
||||
EMS_UART.conf0.txfifo_rst = 1;
|
||||
#endif
|
||||
buf_handle_ = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
|
||||
uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);
|
||||
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 3, NULL);
|
||||
portEXIT_CRITICAL(&mux_);
|
||||
restart();
|
||||
uart_driver_install(EMSUART_NUM, 129, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
|
||||
uart_param_config(EMSUART_NUM, &uart_config);
|
||||
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
uart_set_rx_full_threshold(EMSUART_NUM, 1);
|
||||
uart_set_rx_timeout(EMSUART_NUM, 0); // disable
|
||||
xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, configMAX_PRIORITIES - 1, NULL);
|
||||
}
|
||||
tx_mode_ = tx_mode;
|
||||
uart_enable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop, disable interrupt
|
||||
*/
|
||||
void EMSuart::stop() {
|
||||
portENTER_CRITICAL(&mux_);
|
||||
EMS_UART.int_ena.val = 0; // disable all intr.
|
||||
portEXIT_CRITICAL(&mux_);
|
||||
};
|
||||
|
||||
/*
|
||||
* Restart uart and make mode dependent configs.
|
||||
*/
|
||||
void EMSuart::restart() {
|
||||
portENTER_CRITICAL(&mux_);
|
||||
if (EMS_UART.int_raw.brk_det) { // we received a break in the meantime
|
||||
EMS_UART.int_clr.brk_det = 1; // clear flag
|
||||
drop_next_rx_ = true; // and drop first frame
|
||||
if (tx_mode_ != 0xFF) { // only call after driver initialisation
|
||||
uart_disable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
|
||||
}
|
||||
EMS_UART.int_ena.brk_det = 1; // activate only break
|
||||
EMS_UART.conf0.txd_brk = (tx_mode_ == EMS_TXMODE_HW) ? 1 : 0;
|
||||
portEXIT_CRITICAL(&mux_);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Sends a 1-byte poll, ending with a <BRK>
|
||||
@@ -164,49 +124,46 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
|
||||
}
|
||||
|
||||
if (tx_mode_ == EMS_TXMODE_HW) { // hardware controlled mode
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
EMS_UART.fifo.rw_byte = buf[i];
|
||||
}
|
||||
uart_write_bytes_with_break(EMSUART_NUM, buf, len, 10);
|
||||
return EMS_TX_STATUS_OK;
|
||||
}
|
||||
|
||||
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
EMS_UART.fifo.rw_byte = buf[i];
|
||||
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
||||
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
|
||||
}
|
||||
EMS_UART.conf0.txd_inv = 1; // send <brk>
|
||||
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
|
||||
delayMicroseconds(EMSUART_TX_BRK_PLUS);
|
||||
EMS_UART.conf0.txd_inv = 0;
|
||||
uart_set_line_inverse(EMSUART_NUM, 0);
|
||||
return EMS_TX_STATUS_OK;
|
||||
}
|
||||
|
||||
if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
EMS_UART.fifo.rw_byte = buf[i];
|
||||
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
||||
delayMicroseconds(EMSUART_TX_WAIT_HT3);
|
||||
}
|
||||
EMS_UART.conf0.txd_inv = 1; // send <brk>
|
||||
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
|
||||
delayMicroseconds(EMSUART_TX_BRK_HT3);
|
||||
EMS_UART.conf0.txd_inv = 0;
|
||||
uart_set_line_inverse(EMSUART_NUM, 0);
|
||||
return EMS_TX_STATUS_OK;
|
||||
}
|
||||
|
||||
// mode 1: wait for echo after each byte
|
||||
// flush fifos -- not supported in ESP32 uart #2!
|
||||
// EMS_UART.conf0.rxfifo_rst = 1;
|
||||
// EMS_UART.conf0.txfifo_rst = 1;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
|
||||
EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte
|
||||
size_t rx0, rx1;
|
||||
uart_get_buffered_data_len(EMSUART_NUM, &rx0);
|
||||
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
||||
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
|
||||
while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) {
|
||||
do {
|
||||
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
|
||||
uart_get_buffered_data_len(EMSUART_NUM, &rx1);
|
||||
} while ((rx1 == rx0) && (--timeoutcnt));
|
||||
}
|
||||
}
|
||||
EMS_UART.conf0.txd_inv = 1;
|
||||
uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV);
|
||||
delayMicroseconds(EMSUART_TX_BRK_EMS);
|
||||
EMS_UART.conf0.txd_inv = 0;
|
||||
uart_set_line_inverse(EMSUART_NUM, 0);
|
||||
return EMS_TX_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,24 +20,14 @@
|
||||
/*
|
||||
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380
|
||||
*/
|
||||
#if defined(ESP32)
|
||||
|
||||
#ifndef EMSESP_EMSUART_H
|
||||
#define EMSESP_EMSUART_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "freertos/queue.h"
|
||||
#include <driver/uart.h>
|
||||
#include <driver/timer.h>
|
||||
|
||||
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK
|
||||
|
||||
#define EMSUART_UART UART_NUM_2 // on the ESP32 we're using UART2
|
||||
#define EMS_UART UART2 // for intr setting
|
||||
#define EMSUART_NUM UART_NUM_2 // on the ESP32 we're using UART2
|
||||
#define EMSUART UART2 // for intr setting
|
||||
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
|
||||
|
||||
#define EMS_TXMODE_DEFAULT 1
|
||||
@@ -78,12 +68,9 @@ class EMSuart {
|
||||
static uint16_t transmit(const uint8_t * buf, const uint8_t len);
|
||||
|
||||
private:
|
||||
static void emsuart_recvTask(void * para);
|
||||
static void IRAM_ATTR emsuart_rx_intr_handler(void * para);
|
||||
static void restart();
|
||||
static void uart_event_task(void * pvParameters);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.4.1"
|
||||
#define EMSESP_APP_VERSION "3.4.2"
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// SUrlParser from https://github.com/Mad-ness/simple-url-parser
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
@@ -158,7 +156,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
||||
}
|
||||
|
||||
void WebAPIService::getSettings(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["type"] = "settings";
|
||||
@@ -179,7 +177,7 @@ void WebAPIService::getSettings(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
void WebAPIService::getCustomizations(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||
auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["type"] = "customizations";
|
||||
|
||||
@@ -148,7 +148,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
||||
// deletes the customization file
|
||||
void WebCustomizationService::reset_customization(AsyncWebServerRequest * request) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (LITTLEFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
|
||||
if (LittleFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
|
||||
AsyncWebServerResponse * response = request->beginResponse(200); // OK
|
||||
request->send(response);
|
||||
EMSESP::system_.restart_requested(true);
|
||||
@@ -165,22 +165,27 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// list is already sorted by device type
|
||||
// controller is ignored since it doesn't have any associated entities
|
||||
JsonArray devices = root.createNestedArray("devices");
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->has_entities()) {
|
||||
JsonObject obj = devices.createNestedObject();
|
||||
obj["i"] = emsdevice->unique_id(); // a unique id
|
||||
obj["i"] = emsdevice->unique_id(); // its unique id
|
||||
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; // shortname
|
||||
|
||||
// device type name. We may have one than one (e.g. multiple thermostats) so postfix name with index
|
||||
// code block not needed - see https://github.com/emsesp/EMS-ESP32/pull/586#issuecomment-1193779668
|
||||
/*
|
||||
uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id());
|
||||
if (device_index) {
|
||||
char s[10];
|
||||
obj["s"] = emsdevice->device_type_name() + Helpers::smallitoa(s, device_index) + " (" + emsdevice->name() + ")"; // shortname - we prefix the count to make it unique
|
||||
obj["t"] = Helpers::toLower(emsdevice->device_type_name()) + Helpers::smallitoa(s, device_index);
|
||||
} else {
|
||||
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")";
|
||||
obj["t"] = Helpers::toLower(emsdevice->device_type_name());
|
||||
}
|
||||
*/
|
||||
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")";
|
||||
obj["t"] = Helpers::toLower(emsdevice->device_type_name());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
// list is already sorted by device type
|
||||
// Ignore Contoller
|
||||
JsonArray devices = root.createNestedArray("devices");
|
||||
char buffer[3];
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
// ignore controller
|
||||
if (emsdevice && (emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER || emsdevice->count_entities() > 0)) {
|
||||
JsonObject obj = devices.createNestedObject();
|
||||
obj["id"] = Helpers::smallitoa(buffer, emsdevice->unique_id()); // a unique id as a string
|
||||
@@ -94,6 +94,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||
// sensors stuff
|
||||
root["active_sensors"] = EMSESP::dallassensor_.no_sensors() + (EMSESP::analogsensor_.analog_enabled() ? EMSESP::analogsensor_.no_sensors() : 0);
|
||||
root["analog_enabled"] = EMSESP::analogsensor_.analog_enabled();
|
||||
root["connected"] = EMSESP::bus_status() != 2;
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
@@ -45,7 +45,6 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
|
||||
root["syslog_mark_interval"] = settings.syslog_mark_interval;
|
||||
root["syslog_host"] = settings.syslog_host;
|
||||
root["syslog_port"] = settings.syslog_port;
|
||||
root["master_thermostat"] = settings.master_thermostat;
|
||||
root["shower_timer"] = settings.shower_timer;
|
||||
root["shower_alert"] = settings.shower_alert;
|
||||
root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
|
||||
@@ -108,10 +107,10 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
||||
check_flag(prev, settings.tx_mode, ChangeFlags::UART);
|
||||
prev = settings.rx_gpio;
|
||||
settings.rx_gpio = root["rx_gpio"] | default_rx_gpio;
|
||||
check_flag(prev, settings.rx_gpio, ChangeFlags::UART);
|
||||
check_flag(prev, settings.rx_gpio, ChangeFlags::RESTART);
|
||||
prev = settings.tx_gpio;
|
||||
settings.tx_gpio = root["tx_gpio"] | default_tx_gpio;
|
||||
check_flag(prev, settings.tx_gpio, ChangeFlags::UART);
|
||||
check_flag(prev, settings.tx_gpio, ChangeFlags::RESTART);
|
||||
|
||||
// syslog
|
||||
prev = settings.syslog_enabled;
|
||||
@@ -204,10 +203,6 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
||||
settings.low_clock = root["low_clock"] | false;
|
||||
check_flag(prev, settings.low_clock, ChangeFlags::RESTART);
|
||||
|
||||
prev = settings.master_thermostat;
|
||||
settings.master_thermostat = root["master_thermostat"] | EMSESP_DEFAULT_MASTER_THERMOSTAT;
|
||||
check_flag(prev, settings.master_thermostat, ChangeFlags::RESTART);
|
||||
|
||||
//
|
||||
// without checks...
|
||||
//
|
||||
@@ -279,6 +274,7 @@ void WebSettingsService::onUpdate() {
|
||||
|
||||
void WebSettingsService::begin() {
|
||||
_fsPersistence.readFromFS();
|
||||
WebSettings::reset_flags();
|
||||
}
|
||||
|
||||
void WebSettingsService::save() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user