From 8eda64d30fa6a63718ae2a3873836341400477fa Mon Sep 17 00:00:00 2001 From: Jerome Douven Date: Sun, 11 Oct 2026 12:36:20 +1000 Subject: [PATCH 1/2] fix(1P): treat Meter register 326 as a bitfield Register 326 (Ex_MeterCT) packs meter enable, phase, direction and meter type into one word, so real values such as 0x0383 (SDM230 on phase A) matched no option and logged 'No option found for mapping 899'. Map only bit0 to Disable/Enable and preserve the other bits on write. Drop the bogus 'Generator: 13' option. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../packages/deye_hybrid_1p/device.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pv_inverter/packages/deye_hybrid_1p/device.yaml b/pv_inverter/packages/deye_hybrid_1p/device.yaml index 1e17d05..3b9e510 100644 --- a/pv_inverter/packages/deye_hybrid_1p/device.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/device.yaml @@ -11,6 +11,11 @@ # 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. +globals: + - id: meter_ct_raw + type: int32_t + initial_value: "-1" + sensor: - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -383,4 +388,16 @@ select: optionsmap: "Disable": 0 "Enable": 1 - "Generator": 13 + # Register 326 (Ex_MeterCT) is a bitfield per the V119 protocol: bit0 = + # meter enable, bits1-3 = phase A/B/C, bits6-7 = direction, bits8-11 = meter + # type, bits12-15 = meter 2. Only bit0 is mapped here; the raw value is kept + # so writes preserve the other bits. + lambda: |- + id(meter_ct_raw) = x; + return (x & 0x0001) ? std::string("Enable") : std::string("Disable"); + write_lambda: |- + if (id(meter_ct_raw) < 0) { + ESP_LOGW("meter", "Register 326 not read yet - write skipped"); + return {}; + } + return (id(meter_ct_raw) & ~0x0001) | (value & 0x0001); From 8af80a3ef4a558d7241817e7b3634585fd5ebdb0 Mon Sep 17 00:00:00 2001 From: Jerome Douven Date: Sun, 11 Oct 2026 12:40:10 +1000 Subject: [PATCH 2/2] fix(1P): treat Charging Signal register 242 as a bitfield Only bits0-1 hold the grid/generator signal; the upper byte carries other data on some inverters (e.g. 0x5F01), which matched no option and logged 'No option found for mapping 24321'. Map bits0-1 and preserve the rest on write. Co-Authored-By: Claude Opus 5.5 (1M context) --- pv_inverter/packages/deye_hybrid_1p/grid.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pv_inverter/packages/deye_hybrid_1p/grid.yaml b/pv_inverter/packages/deye_hybrid_1p/grid.yaml index ee2e195..809ed74 100644 --- a/pv_inverter/packages/deye_hybrid_1p/grid.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/grid.yaml @@ -25,6 +25,9 @@ globals: - id: last_update_time type: unsigned long restore_value: yes + - id: gen_grid_signal_raw + type: int32_t + initial_value: "-1" sensor: # Register 54 = "AC power ratio". Per the V119 protocol, the AC power registers @@ -324,6 +327,23 @@ select: "Grid": 1 "Generator": 2 "Both": 3 + # Register 242 (Gen_Grid_Signal): bit0 = grid signal, bit1 = generator + # signal. The upper bits carry other data on some inverters (e.g. 0x5F01), + # so only bits0-1 are mapped and the rest are preserved on write. + lambda: |- + id(gen_grid_signal_raw) = x; + switch (x & 0x0003) { + case 1: return std::string("Grid"); + case 2: return std::string("Generator"); + case 3: return std::string("Both"); + default: return std::string("Normal"); + } + write_lambda: |- + if (id(gen_grid_signal_raw) < 0) { + ESP_LOGW("charging_signal", "Register 242 not read yet - write skipped"); + return {}; + } + return (id(gen_grid_signal_raw) & ~0x0003) | (value & 0x0003); switch: - platform: modbus_controller