mirror of https://github.com/arendst/Tasmota.git
Merge branch 'development' into prerelease-14.3.0
This commit is contained in:
commit
59409aedb2
|
@ -16,6 +16,11 @@ All notable changes to this project will be documented in this file.
|
|||
- Command ``DaliSend <address>|<address+256>,<command>`` to send command (address+256 is repeat) on DALI bus
|
||||
- Command ``DaliQuery <address>|<address+256>,<command>`` to send command (address+256 is repeat) on DALI bus and wait up to DALI_TIMEOUT ms for response
|
||||
- Berry Serial `config` to change parity on-the-fly for RS-485 (#22285)
|
||||
- Misubishi Electric HVAC Heat/Dry/Cool Auto operation mode (#22216)
|
||||
- Misubishi Electric HVAC Bridge to HomeBridge/Homekit locally (#22236)
|
||||
- Misubishi Electric HVAC Air Direction Control (#22241)
|
||||
- Misubishi Electric HVAC prohibit function (#22269)
|
||||
- Misubishi Electric HVAC compressor map and operation power and energy (#22290)
|
||||
|
||||
### Changed
|
||||
- ESP32 platform update from 2024.09.10 to 2024.09.30 and Framework (Arduino Core) from v3.0.5 to v3.1.0.240926 (#22203)
|
||||
|
@ -59,10 +64,6 @@ All notable changes to this project will be documented in this file.
|
|||
- ESP8266 experimental support for second I2C bus
|
||||
- Berry improve `int64` constructor (#22172)
|
||||
- MQTT warning if trying to connect without TLS on a port that normally uses TLS (#22175)
|
||||
- Misubishi Electric HVAC Heat/Dry/Cool ISEE operation mode (#22216)
|
||||
- Misubishi Electric HVAC Bridge to HomeBridge/Homekit locally (#22236)
|
||||
- Misubishi Electric HVAC Air Direction Control (#22241)
|
||||
- Misubishi Electric HVAC prohibit function (#22269)
|
||||
|
||||
### Changed
|
||||
- Refactored I2C drivers HTU21, BH1750, SHT3x, iAQ and HYT
|
||||
|
|
|
@ -136,10 +136,11 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
|||
- Support nexus protocol and calculation of separation limit to rc-switch library [#21886](https://github.com/arendst/Tasmota/issues/21886)
|
||||
- KNX additional KnxTx functions and define KNX_USE_DPT9 [#22071](https://github.com/arendst/Tasmota/issues/22071)
|
||||
- SML multi TRX line [#22056](https://github.com/arendst/Tasmota/issues/22056)
|
||||
- Misubishi Electric HVAC Heat/Dry/Cool ISEE operation mode [#22216](https://github.com/arendst/Tasmota/issues/22216)
|
||||
- Misubishi Electric HVAC Heat/Dry/Cool Auto operation mode [#22216](https://github.com/arendst/Tasmota/issues/22216)
|
||||
- Misubishi Electric HVAC Bridge to HomeBridge/Homekit locally [#22236](https://github.com/arendst/Tasmota/issues/22236)
|
||||
- Misubishi Electric HVAC Air Direction Control [#22241](https://github.com/arendst/Tasmota/issues/22241)
|
||||
- Misubishi Electric HVAC prohibit function [#22269](https://github.com/arendst/Tasmota/issues/22269)
|
||||
- Misubishi Electric HVAC compressor map and operation power and energy [#22290](https://github.com/arendst/Tasmota/issues/22290)
|
||||
- Zigbee Koenkk firmware 20240710 for Sonoff Zigbee ZBPro [#22076](https://github.com/arendst/Tasmota/issues/22076)
|
||||
- Berry Zigbee improvements to prepare Matter [#22083](https://github.com/arendst/Tasmota/issues/22083)
|
||||
- Berry virtual Energy driver [#22134](https://github.com/arendst/Tasmota/issues/22134)
|
||||
|
|
|
@ -24,43 +24,6 @@ class Leds_animation_UI
|
|||
"<form id=but_part_mgr style='display: block;' action='leds_anim' method='get'><button>Leds animation</button></form><p></p>")
|
||||
end
|
||||
|
||||
#- ---------------------------------------------------------------------- -#
|
||||
#- Show page to migrate to factory layout + single OTA
|
||||
#- ---------------------------------------------------------------------- -#
|
||||
def show_migrate_to_factory(p)
|
||||
# display ota partitions
|
||||
import webserver
|
||||
import string
|
||||
|
||||
if !self.factory_migrate_eligible(p) return end
|
||||
|
||||
webserver.content_send("<fieldset><legend><b> Migrate to safeboot partition layout </b></legend><p></p>")
|
||||
|
||||
webserver.content_send("<p>The `safeboot` layout allows for increased size<br>of firmware or file-system.</p>")
|
||||
webserver.content_send("<p>Please see <a href='https://tasmota.github.io/docs/Safeboot/' target='_blank'>Safeboot layout documentation</a></p>")
|
||||
webserver.content_send("<p> </p>")
|
||||
|
||||
webserver.content_send(string.format("<p>Step 1: %s</p>", self.display_step_state(self.test_step_1(p), "boot on `app1`")))
|
||||
webserver.content_send(string.format("<p>Step 2: %s</p>", self.display_step_state(self.test_step_2(p), "flash `safeboot` to `app0`")))
|
||||
webserver.content_send(string.format("<p>Step 3: %s</p>", self.display_step_state(self.test_step_3(p), "change partition map")))
|
||||
webserver.content_send(string.format("<p>Step 4: %s</p>", self.display_step_state(self.test_step_4(p), "flash final firmware")))
|
||||
|
||||
webserver.content_send("<form action='/part_wiz' method='post' ")
|
||||
webserver.content_send("onsubmit='return confirm(\"This will cause multiple restarts.\");'>")
|
||||
var ota_url = tasmota.cmd("OtaUrl").find("OtaUrl", "")
|
||||
webserver.content_send(string.format("<br><b>OTA Url</b><br><input id='o1' placeholder='OTA_URL' value='%s'><br>",
|
||||
ota_url))
|
||||
|
||||
import persist
|
||||
var safeboot_url = persist.find("safeboot_url", self.default_safeboot_URL())
|
||||
webserver.content_send(string.format("<br><b>SAFEBOOT Url</b> (don't change)<input id='o2' placeholder='SAFEBOOT_URL' value='%s'><br>",
|
||||
safeboot_url))
|
||||
|
||||
webserver.content_send("<p></p><button name='factory' class='button bred'>Start migration</button></form></p>")
|
||||
|
||||
webserver.content_send("<p></p></fieldset><p></p>")
|
||||
end
|
||||
|
||||
#######################################################################
|
||||
# Show background colors
|
||||
#######################################################################
|
||||
|
|
|
@ -91,8 +91,14 @@ struct miel_hvac_data_roomtemp {
|
|||
|
||||
struct miel_hvac_data_status {
|
||||
uint8_t _pad1[2];
|
||||
uint8_t _pad2[1];
|
||||
uint8_t compressor;
|
||||
uint8_t operation;
|
||||
#define MIEL_HVAC_STATUS_COMPRESSOR_OFF 0x00
|
||||
#define MIEL_HVAC_STATUS_COMPRESSOR_ON 0x01
|
||||
uint8_t operationpower;
|
||||
uint8_t operationpower1;
|
||||
uint8_t operationenergy;
|
||||
uint8_t operationenergy1;
|
||||
};
|
||||
|
||||
struct miel_hvac_data {
|
||||
|
@ -130,6 +136,12 @@ CTASSERT(offsetof(struct miel_hvac_data, data.settings.airdirection) == 14);
|
|||
CTASSERT(offsetof(struct miel_hvac_data, data.roomtemp.temp) == 3);
|
||||
CTASSERT(offsetof(struct miel_hvac_data, data.roomtemp.temp05) == 6);
|
||||
|
||||
CTASSERT(offsetof(struct miel_hvac_data, data.status.compressor) == 4);
|
||||
CTASSERT(offsetof(struct miel_hvac_data, data.status.operationpower) == 5);
|
||||
CTASSERT(offsetof(struct miel_hvac_data, data.status.operationpower1) == 6);
|
||||
CTASSERT(offsetof(struct miel_hvac_data, data.status.operationenergy) == 7);
|
||||
CTASSERT(offsetof(struct miel_hvac_data, data.status.operationenergy1) == 8);
|
||||
|
||||
/* to hvac */
|
||||
|
||||
#define MIEL_HVAC_H_TYPE_CONNECT 0x5a
|
||||
|
@ -206,7 +218,7 @@ struct miel_hvac_msg_update {
|
|||
uint8_t _pad1[4];
|
||||
uint8_t widevane;
|
||||
#define MIEL_HVAC_UPDATE_WIDEVANE_MASK 0x0f
|
||||
#define MIEL_HVAC_UPDATE_WIDEVANE_ISEE 0x00
|
||||
#define MIEL_HVAC_UPDATE_WIDEVANE_AUTO 0x00
|
||||
#define MIEL_HVAC_UPDATE_WIDEVANE_LL 0x01
|
||||
#define MIEL_HVAC_UPDATE_WIDEVANE_L 0x02
|
||||
#define MIEL_HVAC_UPDATE_WIDEVANE_C 0x03
|
||||
|
@ -304,6 +316,11 @@ struct miel_hvac_map {
|
|||
const char *name;
|
||||
};
|
||||
|
||||
static const struct miel_hvac_map miel_hvac_power_map[] = {
|
||||
{ MIEL_HVAC_UPDATE_POWER_OFF, "off" },
|
||||
{ MIEL_HVAC_UPDATE_POWER_ON, "on" },
|
||||
};
|
||||
|
||||
static const struct miel_hvac_map miel_hvac_mode_map[] = {
|
||||
{ MIEL_HVAC_UPDATE_MODE_HEAT, "heat" },
|
||||
{ MIEL_HVAC_UPDATE_MODE_DRY, "dry" },
|
||||
|
@ -335,7 +352,7 @@ static const struct miel_hvac_map miel_hvac_vane_map[] = {
|
|||
};
|
||||
|
||||
static const struct miel_hvac_map miel_hvac_widevane_map[] = {
|
||||
{ MIEL_HVAC_UPDATE_WIDEVANE_ISEE, "isee" },
|
||||
{ MIEL_HVAC_UPDATE_WIDEVANE_AUTO, "auto" },
|
||||
{ MIEL_HVAC_UPDATE_WIDEVANE_LL, "left" },
|
||||
{ MIEL_HVAC_UPDATE_WIDEVANE_L, "left_middle" },
|
||||
{ MIEL_HVAC_UPDATE_WIDEVANE_C, "center" },
|
||||
|
@ -362,6 +379,11 @@ static const struct miel_hvac_map miel_hvac_airdirection_map[] = {
|
|||
{ MIEL_HVAC_UPDATE_AIRDIRECTION_DIRECT, "direct" },
|
||||
};
|
||||
|
||||
static const struct miel_hvac_map miel_hvac_compressor_map[] = {
|
||||
{ MIEL_HVAC_STATUS_COMPRESSOR_OFF, "off" },
|
||||
{ MIEL_HVAC_STATUS_COMPRESSOR_ON, "on" },
|
||||
};
|
||||
|
||||
enum miel_hvac_parser_state {
|
||||
MIEL_HVAC_P_START,
|
||||
MIEL_HVAC_P_TYPE,
|
||||
|
@ -997,8 +1019,12 @@ miel_hvac_publish_settings(struct miel_hvac_softc *sc)
|
|||
const char *name;
|
||||
const char *name_swing_h;
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_IRHVAC_POWER "\":\"%s\""),
|
||||
set->power ? "ON" : "OFF");
|
||||
name = miel_hvac_map_byval(set->power,
|
||||
miel_hvac_power_map, nitems(miel_hvac_power_map));
|
||||
if (name != NULL) {
|
||||
Response_P(PSTR("{\"" D_JSON_IRHVAC_POWER "\":\"%s\""),
|
||||
name);
|
||||
}
|
||||
|
||||
name = miel_hvac_map_byval( set->mode &
|
||||
MIEL_HVAC_SETTINGS_MODE_MASK,
|
||||
|
@ -1046,7 +1072,7 @@ miel_hvac_publish_settings(struct miel_hvac_softc *sc)
|
|||
miel_hvac_airdirection_map, nitems(miel_hvac_airdirection_map));
|
||||
if (name != NULL) {
|
||||
ResponseAppend_P(PSTR(",\"AirDirection\":\"%s\""),
|
||||
name_swing_h == "isee" ? name : "OFF");
|
||||
name_swing_h == "auto" ? name : "OFF");
|
||||
}
|
||||
|
||||
name = miel_hvac_map_byval(set->prohibit,
|
||||
|
@ -1236,8 +1262,13 @@ miel_hvac_sensor(struct miel_hvac_softc *sc)
|
|||
const char *name_swing_h;
|
||||
|
||||
ResponseAppend_P(PSTR("," "\"MiElHVAC\":{"));
|
||||
ResponseAppend_P(PSTR("\"Power\":\"%s\""),
|
||||
set->power ? "ON" : "OFF");
|
||||
|
||||
name = miel_hvac_map_byval(set->power,
|
||||
miel_hvac_power_map, nitems(miel_hvac_power_map));
|
||||
if (name != NULL) {
|
||||
ResponseAppend_P(PSTR("\"Power\":\"%s\""),
|
||||
name);
|
||||
}
|
||||
|
||||
name = miel_hvac_map_byval( set->mode &
|
||||
MIEL_HVAC_SETTINGS_MODE_MASK,
|
||||
|
@ -1283,7 +1314,7 @@ miel_hvac_sensor(struct miel_hvac_softc *sc)
|
|||
miel_hvac_airdirection_map, nitems(miel_hvac_airdirection_map));
|
||||
if (name != NULL) {
|
||||
ResponseAppend_P(PSTR(",\"AirDirection\":\"%s\""),
|
||||
name_swing_h == "isee" ? name : "OFF");
|
||||
name_swing_h == "auto" ? name : "off");
|
||||
}
|
||||
|
||||
name = miel_hvac_map_byval(set->prohibit,
|
||||
|
@ -1317,13 +1348,28 @@ miel_hvac_sensor(struct miel_hvac_softc *sc)
|
|||
}
|
||||
|
||||
if (sc->sc_status.type != 0) {
|
||||
const struct miel_hvac_data_status *s =
|
||||
const struct miel_hvac_data_status *status =
|
||||
&sc->sc_status.data.status;
|
||||
|
||||
ResponseAppend_P(PSTR(",\"Operation\":\"%s\""),
|
||||
s->operation ? "ON" : "OFF");
|
||||
ResponseAppend_P(PSTR(",\"Compressor\":\"%s\""),
|
||||
s->compressor ? "ON" : "OFF");
|
||||
name = miel_hvac_map_byval(status->compressor,
|
||||
miel_hvac_compressor_map, nitems(miel_hvac_compressor_map));
|
||||
if (name != NULL) {
|
||||
ResponseAppend_P(PSTR(",\"Compressor\":\"%s\""),
|
||||
name);
|
||||
}
|
||||
|
||||
uint16_t combined_power = ((uint16_t)status->operationpower << 8) | (uint16_t)status->operationpower1;
|
||||
char operationpower[33];
|
||||
dtostrfd((float)combined_power, 0, operationpower);
|
||||
ResponseAppend_P(PSTR(",\"OperationPower\":\"%s\""),
|
||||
operationpower);
|
||||
|
||||
uint16_t combined_energy = ((uint16_t)status->operationenergy << 8) | (uint16_t)status->operationenergy1;
|
||||
float operationenergy_in_kWh = (float)combined_energy / 10.0;
|
||||
char operationenergy[33];
|
||||
dtostrfd((float)operationenergy_in_kWh, 1, operationenergy);
|
||||
ResponseAppend_P(PSTR(",\"OperationEnergy\":\"%s\""),
|
||||
operationenergy);
|
||||
}
|
||||
|
||||
if (sc->sc_temp.type != 0) {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
--------------------------------------------------------------------------------------------
|
||||
Version yyyymmdd Action Description
|
||||
--------------------------------------------------------------------------------------------
|
||||
0.1.0.6 20241014 update - Fix received light command loop
|
||||
- Add send collision detection
|
||||
0.1.0.5 20241014 update - Add command `DaliSend [repeat]<address>,<command>`
|
||||
- Add command `DaliQuery [repeat]<address>,<command>`
|
||||
- Send frame twice (repeat) for DALI defined commands
|
||||
|
@ -93,6 +95,7 @@ struct DALI {
|
|||
bool power;
|
||||
bool available;
|
||||
bool response;
|
||||
bool light_sync;
|
||||
} *Dali = nullptr;
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -191,19 +194,40 @@ void DaliSendDataOnce(uint16_t send_dali_data) {
|
|||
1 2 3
|
||||
*/
|
||||
bool bit_value;
|
||||
bool pin_value;
|
||||
bool collision = false;
|
||||
uint32_t bit_pos = 15;
|
||||
uint32_t wait = ESP.getCycleCount();
|
||||
for (uint32_t i = 0; i < 35; i++) { // 417 * 35 = 14.7 ms
|
||||
if (0 == (i &1)) { // Even bit
|
||||
// Start bit, Stop bit, Data bits
|
||||
bit_value = (0 == i) ? 1 : (34 == i) ? 0 : (bool)((send_dali_data >> bit_pos--) &1); // MSB first
|
||||
} else { // Odd bit
|
||||
bit_value = !bit_value; // Complement bit
|
||||
uint32_t bit_number = 0;
|
||||
while (bit_number < 35) { // 417 * 35 = 14.7 ms
|
||||
if (!collision) {
|
||||
if (0 == (bit_number &1)) { // Even bit
|
||||
// Start bit, Stop bit, Data bits
|
||||
bit_value = (0 == bit_number) ? 1 : (34 == bit_number) ? 0 : (bool)((send_dali_data >> bit_pos--) &1); // MSB first
|
||||
} else { // Odd bit
|
||||
bit_value = !bit_value; // Complement bit
|
||||
}
|
||||
pin_value = bit_value ? LOW : HIGH; // Invert bit
|
||||
} else {
|
||||
if (34 == bit_number) {
|
||||
pin_value = HIGH; // Set to idle
|
||||
}
|
||||
}
|
||||
bool pin_value = bit_value ? LOW : HIGH; // Invert bit
|
||||
|
||||
digitalWrite(Dali->pin_tx, (pin_value == DALI_OUT_INVERT) ? LOW : HIGH);
|
||||
wait += Dali->bit_time; // Auto roll-over
|
||||
while (ESP.getCycleCount() < wait);
|
||||
|
||||
if (!collision) {
|
||||
if ((HIGH == pin_value) && (LOW == digitalRead(Dali->pin_rx))) { // Collision if write is 1 and bus is 0
|
||||
collision = true;
|
||||
pin_value = LOW;
|
||||
bit_number = 29; // Keep bus low for 4 bits
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: Send collision"));
|
||||
}
|
||||
}
|
||||
|
||||
bit_number++;
|
||||
}
|
||||
// delayMicroseconds(1100); // Adds to total 15.8 ms
|
||||
}
|
||||
|
@ -293,18 +317,20 @@ void DaliInput(void) {
|
|||
if (DALI_BROADCAST_DP == Dali->address) {
|
||||
uint8_t dimmer_old = changeUIntScale(Dali->dimmer, 0, 254, 0, 100);
|
||||
uint8_t power_old = Dali->power;
|
||||
Dali->power = (Dali->command); // State
|
||||
Dali->power = (Dali->command); // State
|
||||
if (Dali->power) {
|
||||
Dali->dimmer = Dali->command; // Value
|
||||
Dali->dimmer = Dali->command; // Value
|
||||
}
|
||||
if (Settings->sbflag1.dali_web) { // DaliWeb 1
|
||||
if (Settings->sbflag1.dali_web) { // DaliWeb 1
|
||||
uint8_t dimmer_new = changeUIntScale(Dali->dimmer, 0, 254, 0, 100);
|
||||
if (power_old != Dali->power) {
|
||||
Dali->light_sync = true; // Block local loop
|
||||
ExecuteCommandPower(LightDevice(), Dali->power, SRC_SWITCH);
|
||||
}
|
||||
else if (dimmer_old != dimmer_new) {
|
||||
char scmnd[20];
|
||||
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), dimmer_new);
|
||||
Dali->light_sync = true; // Block local loop
|
||||
ExecuteCommand(scmnd, SRC_SWITCH);
|
||||
}
|
||||
show_response = false;
|
||||
|
@ -316,9 +342,9 @@ void DaliInput(void) {
|
|||
}
|
||||
#else
|
||||
if (DALI_BROADCAST_DP == Dali->address) {
|
||||
Dali->power = (Dali->command); // State
|
||||
Dali->power = (Dali->command); // State
|
||||
if (Dali->power) {
|
||||
Dali->dimmer = Dali->command; // Value
|
||||
Dali->dimmer = Dali->command; // Value
|
||||
}
|
||||
}
|
||||
ResponseDali();
|
||||
|
@ -328,6 +354,21 @@ void DaliInput(void) {
|
|||
Dali->available = false;
|
||||
}
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
bool DaliSetChannels(void) {
|
||||
if (Settings->sbflag1.dali_web) { // DaliWeb 1
|
||||
if (Dali->light_sync) { // Block local loop
|
||||
Dali->light_sync = false;
|
||||
} else {
|
||||
uint8_t value = ((uint8_t*)XdrvMailbox.data)[0];
|
||||
if (255 == value) { value = 254; } // Max Dali value
|
||||
DaliPower(value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // USE_LIGHT
|
||||
|
||||
bool DaliInit(void) {
|
||||
if (!PinUsed(GPIO_DALI_TX) || !PinUsed(GPIO_DALI_RX)) { return false; }
|
||||
|
||||
|
@ -366,17 +407,6 @@ bool DaliInit(void) {
|
|||
#endif // USE_LIGHT
|
||||
}
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
bool DaliSetChannels(void) {
|
||||
if (Settings->sbflag1.dali_web) { // DaliWeb 1
|
||||
uint8_t value = ((uint8_t*)XdrvMailbox.data)[0];
|
||||
if (255 == value) { value = 254; } // Max Dali value
|
||||
DaliPower(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // USE_LIGHT
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Experimental - Not functioning
|
||||
\*********************************************************************************************/
|
||||
|
|
Loading…
Reference in New Issue