Merge pull request #2947 from MichaelDvP/dev

save scheduler, custom to nvs, fix #2946
This commit is contained in:
Proddy
2026-02-10 19:39:59 +01:00
committed by GitHub
15 changed files with 2105 additions and 2067 deletions

View File

@@ -17,3 +17,5 @@ For more details go to [emsesp.org](https://emsesp.org/).
- weblogbuffer up to 1000 messages with PSRAM, mentioned in [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
- validate custom entity writes, [#2931](https://github.com/emsesp/EMS-ESP32/issues/2931)
- remove wrong burnMinPower [#2918](https://github.com/emsesp/EMS-ESP32/issues/2918)
- store scheduler active state to nvs [#2946](https://github.com/emsesp/EMS-ESP32/discussions/2946)
- translated modes `heat` and `eco` for HA-climate mode-str-tpl

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -48,16 +48,16 @@
},
"devDependencies": {
"@babel/core": "^7.29.0",
"@eslint/js": "^9.39.2",
"@eslint/js": "^10.0.1",
"@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.3",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/node": "^25.2.2",
"@types/react": "^19.2.13",
"@types/react-dom": "^19.2.3",
"axe-core": "^4.11.1",
"concurrently": "^9.2.1",
"eslint": "^9.39.2",
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.1",
"rollup-plugin-visualizer": "^6.0.5",
@@ -65,7 +65,7 @@
"typescript-eslint": "^8.54.0",
"vite": "^7.3.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^6.0.5"
"vite-tsconfig-paths": "^6.1.0"
},
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
"packageManager": "pnpm@10.29.2"
}

668
interface/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -310,13 +310,15 @@ const CustomEntities = () => {
/>
)}
</Cell>
<Cell>{ei.ram > 0 ? '' : showHex(ei.device_id as number, 2)}</Cell>
<Cell>{ei.ram > 0 ? '' : showHex(ei.type_id as number, 3)}</Cell>
<Cell>{ei.ram > 0 ? '' : ei.offset}</Cell>
<Cell>
{ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)}
</Cell>
<Cell>{ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)}</Cell>
<Cell>{ei.ram === 1 ? '' : ei.offset}</Cell>
<Cell>
{ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]}
{ei.ram === 1
? 'RAM'
: ei.ram === 2
? 'NVS'
: DeviceValueTypeNames[ei.value_type]}
</Cell>
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
</Row>

View File

@@ -205,9 +205,10 @@ const CustomEntitiesDialog = ({
>
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
<MenuItem value={2}>NVS-{LL.VALUE(1)}</MenuItem>
</TextField>
</Grid>
{editItem.ram === 1 && (
{editItem.ram > 0 && (
<>
<Grid>
<TextField

View File

@@ -67,6 +67,9 @@ class Preferences {
size_t putString(const char * key, String value) {
return 0;
}
bool isKey(const char * key) {
return true;
}
// unused....
@@ -84,7 +87,6 @@ class Preferences {
// size_t putBool(const char * key, bool value);
// size_t putBytes(const char * key, const void * value, size_t len);
// bool isKey(const char * key);
// PreferenceType getType(const char * key);
// int8_t getChar(const char * key, int8_t defaultValue = 0);
// int16_t getShort(const char * key, int16_t defaultValue = 0);

View File

@@ -121,82 +121,83 @@ const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_ma
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTa4), 171, 1), // hpta4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpTw1), 172, 1), // hptw1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(poolSetTemp), 173, 1), // poolsettemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 174, 1), // hpin1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 175, 8), // hpin1opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 183, 1), // hpin2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 184, 8), // hpin2opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 192, 1), // hpin3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 193, 8), // hpin3opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 201, 1), // hpin4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 202, 8), // hpin4opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 210, 1), // maxheatcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 211, 1), // maxheatheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterSource), 212, 1), // auxheatersource
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 213, 1), // pvcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 214, 1), // auxheateronly
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 215, 1), // auxheateroff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 216, 1), // auxheaterstatus
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterLevel), 217, 1), // auxheaterlevel
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 218, 1), // auxheaterdelay
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 219, 1), // auxmaxlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 220, 1), // auxlimitstart
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 221, 1), // auxheatrmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 222, 1), // hphystheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 223, 1), // hphystcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 224, 1), // hphystpool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 225, 1), // silentmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 226, 1), // silentfrom
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 227, 1), // silentto
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 228, 1), // mintempsilent
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 229, 1), // tempparmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 230, 1), // auxheatmix
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 231, 1), // tempdiffheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 232, 1), // tempdiffcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 233, 1), // vpcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 234, 1), // heatcable
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 235, 1), // vc0valve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 236, 1), // primepump
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 237, 1), // primepumpmod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 238, 1), // hp3way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 239, 1), // elheatstep1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 240, 1), // elheatstep2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 241, 1), // elheatstep3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 242, 1), // hpea0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 243, 1), // hppumpmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 244, 1), // fan
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanSpd), 245, 1), // fanspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 246, 1), // shutdown
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 247, 1), // hpcurrpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPowerLimit), 248, 1), // hppowerlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 249, 1), // exhausttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 250, 1), // burngas
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 251, 1), // burngas2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 252, 1), // flamecurr
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 253, 1), // fanwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 254, 1), // ignwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 255, 1), // oilpreheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 256, 1), // burnmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 257, 1), // burnminperiod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 258, 1), // absburnpow
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 259, 1), // heatblock
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 260, 1), // boilhyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 261, 1), // boilhystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 262, 1), // boil2hyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 263, 1), // boil2hystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 264, 1), // curveon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 265, 1), // curvebase
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 266, 1), // curveend
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 267, 1), // summertemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 268, 1), // nofrostmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 269, 1), // nofrosttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 270, 2), // gasmeterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 272, 2), // nrgheat2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 274, 1), // nompower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 275, 1), // netflowtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 276, 1), // heatvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 277, 1), // keepwarmtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 278, 1), // setreturntemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 279, 1), // heating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp4wayValve), 174, 1), // hp4way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput1), 175, 1), // hpin1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn1Opt), 176, 8), // hpin1opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput2), 184, 1), // hpin2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn2Opt), 185, 8), // hpin2opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput3), 193, 1), // hpin3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn3Opt), 194, 8), // hpin3opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpInput4), 202, 1), // hpin4
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpIn4Opt), 203, 8), // hpin4opt
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatComp), 211, 1), // maxheatcomp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(maxHeatHeat), 212, 1), // maxheatheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterSource), 213, 1), // auxheatersource
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(pvCooling), 214, 1), // pvcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOnly), 215, 1), // auxheateronly
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterOff), 216, 1), // auxheateroff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterStatus), 217, 1), // auxheaterstatus
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterLevel), 218, 1), // auxheaterlevel
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeaterDelay), 219, 1), // auxheaterdelay
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxMaxLimit), 220, 1), // auxmaxlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxLimitStart), 221, 1), // auxlimitstart
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMode), 222, 1), // auxheatrmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystHeat), 223, 1), // hphystheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystCool), 224, 1), // hphystcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpHystPool), 225, 1), // hphystpool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentMode), 226, 1), // silentmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentFrom), 227, 1), // silentfrom
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(silentTo), 228, 1), // silentto
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(minTempSilent), 229, 1), // mintempsilent
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempParMode), 230, 1), // tempparmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(auxHeatMixValve), 231, 1), // auxheatmix
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffHeat), 232, 1), // tempdiffheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(tempDiffCool), 233, 1), // tempdiffcool
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(vp_cooling), 234, 1), // vpcooling
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatCable), 235, 1), // heatcable
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(VC0valve), 236, 1), // vc0valve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePump), 237, 1), // primepump
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(primePumpMod), 238, 1), // primepumpmod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hp3wayValve), 239, 1), // hp3way
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep1), 240, 1), // elheatstep1
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep2), 241, 1), // elheatstep2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(elHeatStep3), 242, 1), // elheatstep3
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpEA0), 243, 1), // hpea0
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPumpMode), 244, 1), // hppumpmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpFan), 245, 1), // fan
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanSpd), 246, 1), // fanspd
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpShutdown), 247, 1), // shutdown
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpCurrPower), 248, 1), // hpcurrpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(hpPowerLimit), 249, 1), // hppowerlimit
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(exhaustTemp), 250, 1), // exhausttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas), 251, 1), // burngas
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnGas2), 252, 1), // burngas2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(flameCurr), 253, 1), // flamecurr
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(fanWork), 254, 1), // fanwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(ignWork), 255, 1), // ignwork
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(oilPreHeat), 256, 1), // oilpreheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMaxPower), 257, 1), // burnmaxpower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(burnMinPeriod), 258, 1), // burnminperiod
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(absBurnPow), 259, 1), // absburnpow
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatblock), 260, 1), // heatblock
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOn), 261, 1), // boilhyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boilHystOff), 262, 1), // boilhystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOn), 263, 1), // boil2hyston
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(boil2HystOff), 264, 1), // boil2hystoff
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveOn), 265, 1), // curveon
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveBase), 266, 1), // curvebase
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(curveEnd), 267, 1), // curveend
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(summertemp), 268, 1), // summertemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrostmode), 269, 1), // nofrostmode
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nofrosttemp), 270, 1), // nofrosttemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(gasMeterHeat), 271, 2), // gasmeterheat
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nrgHeat2), 273, 2), // nrgheat2
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(nomPower), 275, 1), // nompower
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(netFlowTemp), 276, 1), // netflowtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatValve), 277, 1), // heatvalve
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(keepWarmTemp), 278, 1), // keepwarmtemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(setReturnTemp), 279, 1), // setreturntemp
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DEVICE_DATA, FL_(heatingOn), 280, 1), // heating
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(nrgWw), 0, 2), // nrg
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(meterWw), 2, 2), // meter
REGISTER_MAPPING(dt::BOILER, TAG_TYPE_DHW, FL_(upTimeCompWw), 4, 2), // uptimecomp

View File

@@ -1377,15 +1377,20 @@ bool Mqtt::publish_ha_climate_config(const DeviceValue & dv, const bool has_room
snprintf(mode_str_tpl,
sizeof(mode_str_tpl),
"{%%if %s%%}off{%%elif %s=='%s'%%}heat{%%elif %s=='%s'%%}heat{%%elif %s=='%s'%%}off{%%elif %s=='%s'%%}off{%%else%%}auto{%%endif%%}",
"{%%if %s%%}off{%%elif %s=='%s'%%}heat{%%elif %s=='%s'%%}heat{%%elif %s=='%s'%%}heat{%%elif %s=='%s'%%}off{%%elif %s=='%s'%%}off{%%elif "
"%s=='%s'%%}off{%%else%%}auto{%%endif%%}",
hc_mode_cond,
hc_mode_s,
Helpers::translated_word(FL_(manual)),
hc_mode_s,
Helpers::translated_word(FL_(day)),
hc_mode_s,
Helpers::translated_word(FL_(heat)),
hc_mode_s,
Helpers::translated_word(FL_(night)),
hc_mode_s,
Helpers::translated_word(FL_(eco)),
hc_mode_s,
Helpers::translated_word(FL_(off)));
snprintf(name_s, sizeof(name_s), "%s%d", tagname, hc_num);

View File

@@ -647,6 +647,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
DeviceValueUOM::DEGREES,
MAKE_CF_CB(set_pool_temp));
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hp4wayValve_, DeviceValueType::ENUM, FL_(enum_4way), FL_(hp4wayValve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hp4wayValve_, DeviceValueType::BOOL, FL_(hp4wayValve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpInput[0].state, DeviceValueType::BOOL, FL_(hpInput1), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&hpInput[0].option,
@@ -1731,7 +1732,9 @@ void Boiler::process_HpPower(std::shared_ptr<const Telegram> telegram) {
has_bitupdate(telegram, hp3wayValve_, 0, 6);
// has_bitupdate(telegram, heating_, 0, 0); // heating on? https://github.com/emsesp/EMS-ESP32/discussions/1898
has_bitupdate(telegram, hpSwitchValve_, 0, 4);
if (coolingType_ == 3) {
has_bitupdate(telegram, hp4wayValve_, 0, 3); // https://github.com/emsesp/EMS-ESP32/issues/2844#issuecomment-3869770845
}
has_bitupdate(telegram, elHeatStep1_, 3, 0);
has_bitupdate(telegram, elHeatStep2_, 3, 1);
has_bitupdate(telegram, elHeatStep3_, 3, 2);
@@ -1831,6 +1834,8 @@ void Boiler::process_HpInConfig(std::shared_ptr<const Telegram> telegram) {
// Boiler(0x08) -W-> Me(0x0B), HpHeaterConfig(0x0485)
void Boiler::process_HpCooling(std::shared_ptr<const Telegram> telegram) {
// coolingtype to set 4wayvalve (0x48D), type not published yet, https://github.com/emsesp/EMS-ESP32/issues/2844#issuecomment-3869770845
has_update(telegram, coolingType_, 0); // none = 0, passive cooling box = 1, active cooling box = 2, 4-way valve = 3, active and passive cooling box = 4.
has_update(telegram, pvCooling_, 21);
}

View File

@@ -270,6 +270,7 @@ class Boiler : public EMSdevice {
uint8_t powerReduction_;
uint8_t pvCooling_;
uint8_t coolingType_;
uint8_t auxHeatMode_;
uint8_t auxMaxLimit_;
uint8_t auxLimitStart_;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.8.2-dev.2"
#define EMSESP_APP_VERSION "3.8.2-dev.3"

View File

@@ -74,6 +74,11 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
if (entityItem.raw) {
delete[] entityItem.raw;
}
if (entityItem.ram == 2) { // NVS
char key[sizeof(entityItem.name) + 2];
snprintf(key, sizeof(key), "c:%s", entityItem.name);
EMSESP::nvs_.remove(key);
}
if (entityItem.ram) { // save name/value pairs for change checking
doc[entityItem.name] = entityItem.value;
}
@@ -95,9 +100,9 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
entityItem.value_type = ei["value_type"];
entityItem.writeable = ei["writeable"];
entityItem.hide = ei["hide"] | false;
entityItem.data = ei["value"].as<std::string>();
entityItem.data = ei["value"].as<std::string>().c_str();
strlcpy(entityItem.name, ei["name"].as<const char *>(), sizeof(entityItem.name));
if (entityItem.ram == 1) {
if (entityItem.ram > 0) {
entityItem.device_id = 0;
entityItem.type_id = 0;
entityItem.value_type = DeviceValueType::STRING;
@@ -127,7 +132,13 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
if (entityItem.factor == 0) {
entityItem.factor = 1;
}
if (entityItem.ram == 2) { // NVS
char key[sizeof(entityItem.name) + 2];
snprintf(key, sizeof(key), "c:%s", entityItem.name);
if (EMSESP::nvs_.isKey(key)) {
entityItem.data = EMSESP::nvs_.getString(key).c_str();
}
}
webCustomEntity.customEntityItems.push_back(entityItem); // add to list
if (entityItem.writeable && entityItem.name[0] != '\0') {
@@ -161,8 +172,18 @@ bool WebCustomEntityService::command_setvalue(const char * value, const int8_t i
for (CustomEntityItem & entityItem : *customEntityItems_) {
if (Helpers::toLower(entityItem.name) == Helpers::toLower(name)) {
if (entityItem.data == value) {
return true; // no change
}
if (entityItem.ram == 1) {
entityItem.data = value;
} else if (entityItem.ram == 2) { // NVS
entityItem.data = value;
char key[sizeof(entityItem.name) + 2];
snprintf(key, sizeof(key), "c:%s", entityItem.name);
if (!EMSESP::nvs_.isKey(key) || EMSESP::nvs_.getString(key) != entityItem.data.c_str()) {
EMSESP::nvs_.putString(key, entityItem.data.c_str());
}
} else if (entityItem.value_type == DeviceValueType::STRING) {
auto telegram = strdup(value);
uint8_t length = strlen(telegram) / 3 + 1;
@@ -337,7 +358,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem const & entity) {
output["name"] = (const char *)entity.name;
output["fullname"] = (const char *)entity.name;
output["storage"] = entity.ram ? "ram" : "ems";
output["storage"] = entity.ram == 1 ? "ram" : entity.ram == 2 ? "nvs" : "ems";
output["type"] = entity.value_type == DeviceValueType::BOOL ? "boolean" : entity.value_type == DeviceValueType::STRING ? "string" : F_(number);
output["readable"] = true;
output["writeable"] = entity.writeable;

View File

@@ -73,6 +73,11 @@ void WebScheduler::read(WebScheduler & webScheduler, JsonObject root) {
StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webScheduler) {
// reset the list
Command::erase_device_commands(EMSdevice::DeviceType::SCHEDULER);
for (ScheduleItem & scheduleItem : webScheduler.scheduleItems) {
char key[sizeof(scheduleItem.name) + 2];
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
EMSESP::nvs_.remove(key);
}
webScheduler.scheduleItems.clear();
EMSESP::webSchedulerService.ha_reset();
@@ -95,6 +100,11 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu
webScheduler.scheduleItems.push_back(si); // add to list
if (webScheduler.scheduleItems.back().name[0] != '\0') {
char key[sizeof(webScheduler.scheduleItems.back().name) + 2];
snprintf(key, sizeof(key), "s:%s", webScheduler.scheduleItems.back().name);
if (EMSESP::nvs_.isKey(key)) {
webScheduler.scheduleItems.back().active = EMSESP::nvs_.getBool(key);
}
Command::add(
EMSdevice::DeviceType::SCHEDULER,
webScheduler.scheduleItems.back().name,
@@ -127,7 +137,21 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id,
if (EMSESP::mqtt_.get_publish_onchange(0)) {
publish();
}
// save new state to nvs #2946
char key[sizeof(scheduleItem.name) + 2];
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
EMSESP::nvs_.putBool(key, scheduleItem.active);
/* save to filesystem
EMSESP::webSchedulerService.update([&](WebScheduler & webSchedule) {
for (auto si : webSchedule.scheduleItems) {
if (!strcmp(si.name, scheduleItem.name)) {
si.active = scheduleItem.active;
break;
}
}
return StateUpdateResult::CHANGED;
});
*/
return true;
}
}
@@ -260,8 +284,8 @@ void WebSchedulerService::publish(const bool force) {
char uniq_s[70];
snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(scheduler), scheduleItem.name);
config["uniq_id"] = uniq_s;
config["name"] = (const char *)scheduleItem.name;
config["uniq_id"] = uniq_s;
config["name"] = (const char *)scheduleItem.name;
// Optimized: use stack buffer instead of string concatenation
char def_ent_id[80];
snprintf(def_ent_id, sizeof(def_ent_id), "switch.%s", uniq_s);