|
458 | 458 | } |
459 | 459 | } |
460 | 460 |
|
| 461 | +# ============================================================================ |
| 462 | +# MIN TL-XH2 — second-generation, VPP-only (Issue #361) |
| 463 | +# ============================================================================ |
| 464 | +# |
| 465 | +# The TL-XH2 serves ONLY the VPP ranges. Every legacy range — base 0-124, storage |
| 466 | +# 1000-1124 and the whole 3000+ block — returns Modbus "Illegal Function". The |
| 467 | +# first-generation MIN_TL_XH_3000_10000_V201 profile above is therefore unusable on |
| 468 | +# this hardware: its PV and battery sensors read from 3000-range addresses that do |
| 469 | +# not exist, and it carries three legacy registers (91, 92, 97) that made the poll |
| 470 | +# abort entirely before v1.1.8. |
| 471 | +# |
| 472 | +# Mapping verified against the Growatt portal by Richardmarkink on a MIN 4200TL-XH2 |
| 473 | +# (DTC 5100, protocol V2.01), rather than assumed from the V2.01 spec blocks: |
| 474 | +# |
| 475 | +# 31011 = 6.3 A portal MPPT1 current 6.3 A |
| 476 | +# 31013 = 6.9 A portal MPPT2 current 6.7 A |
| 477 | +# 31109 = 8.3 A portal grid current L1 8.3 A |
| 478 | +# 31214 = 404.3 V matched the app's battery voltage |
| 479 | +# 31217 = 75 % matched the app's battery SOC |
| 480 | +# 31059 total PV power, confirmed on two scans an order of magnitude |
| 481 | +# apart: 773.5 W vs 747 W computed, 2854.7 W vs 2843 W computed |
| 482 | +# |
| 483 | +# NOTE ON THE PV BLOCK: this does NOT match VPP_V201_PV2_INPUT, which defines |
| 484 | +# 31012/31013 as PV1 power high/low. On TL-XH2 they are PV2 voltage and current. |
| 485 | +# Unpacking that shared block here would report PV2 voltage as PV1 power — a |
| 486 | +# plausible-looking value that would be silently wrong. Defined inline for that |
| 487 | +# reason; do not "simplify" it back to **VPP_V201_PV2_INPUT. |
| 488 | +# |
| 489 | +# PV3 (31014/31015) reads zero on the 4200 because it is a two-string model. The |
| 490 | +# 7-10 kW variants have three strings, so it is defined here rather than omitted — |
| 491 | +# otherwise every larger unit would silently lose a string. |
| 492 | +MIN_TL_XH2_3000_10000_V201 = { |
| 493 | + 'name': 'MIN TL-XH2 3000-10000', |
| 494 | + 'description': 'MIN series TL-XH2 hybrid with battery (3-10kW), VPP-only (30000+/31000+)', |
| 495 | + 'notes': ( |
| 496 | + 'Second-generation TL-XH. Serves ONLY the VPP ranges — legacy 0-124, 1000-1124 ' |
| 497 | + 'and 3000+ all return Illegal Function. PV block layout differs from ' |
| 498 | + 'VPP_V201_PV2_INPUT and is defined inline. Verified against the Growatt portal ' |
| 499 | + 'on a MIN 4200TL-XH2 (Issue #361).' |
| 500 | + ), |
| 501 | + 'input_registers': { |
| 502 | + # === Status (31000-31004) === |
| 503 | + **VPP_V201_STATUS, |
| 504 | + |
| 505 | + # === PV strings — inline, NOT VPP_V201_PV2_INPUT (see note above) === |
| 506 | + 31010: {'name': 'pv1_voltage', 'scale': 0.1, 'unit': 'V', 'desc': 'PV1 DC voltage'}, |
| 507 | + 31011: {'name': 'pv1_current', 'scale': 0.1, 'unit': 'A', 'desc': 'PV1 DC current'}, |
| 508 | + 31012: {'name': 'pv2_voltage', 'scale': 0.1, 'unit': 'V', 'desc': 'PV2 DC voltage'}, |
| 509 | + 31013: {'name': 'pv2_current', 'scale': 0.1, 'unit': 'A', 'desc': 'PV2 DC current'}, |
| 510 | + 31014: {'name': 'pv3_voltage', 'scale': 0.1, 'unit': 'V', |
| 511 | + 'desc': 'PV3 DC voltage (7-10kW models only; 0 on 2-string units)'}, |
| 512 | + 31015: {'name': 'pv3_current', 'scale': 0.1, 'unit': 'A', |
| 513 | + 'desc': 'PV3 DC current (7-10kW models only; 0 on 2-string units)'}, |
| 514 | + |
| 515 | + # === Total PV power (32-bit) === |
| 516 | + # 31058 reads 0 while 31059 carries the value, consistent with a high/low pair. |
| 517 | + # Treated as 32-bit so output above 6.5 kW cannot overflow a single register. |
| 518 | + 31058: {'name': 'pv_total_power_high', 'scale': 1, 'unit': '', 'pair': 31059, |
| 519 | + 'desc': 'Total PV power HIGH word'}, |
| 520 | + 31059: {'name': 'pv_total_power_low', 'scale': 1, 'unit': '', 'pair': 31058, |
| 521 | + 'combined_scale': 0.1, 'combined_unit': 'W', |
| 522 | + 'desc': 'Total PV power LOW word (confirmed on two scans, Issue #361)'}, |
| 523 | + |
| 524 | + # === AC output / grid === |
| 525 | + 31100: {'name': 'ac_power_high', 'scale': 1, 'unit': '', 'pair': 31101, |
| 526 | + 'desc': 'AC output power HIGH word'}, |
| 527 | + 31101: {'name': 'ac_power_low', 'scale': 1, 'unit': '', 'pair': 31100, |
| 528 | + 'combined_scale': 0.1, 'combined_unit': 'W', |
| 529 | + 'desc': 'AC output power LOW word'}, |
| 530 | + 31105: {'name': 'ac_frequency', 'scale': 0.01, 'unit': 'Hz', 'desc': 'Grid frequency'}, |
| 531 | + 31106: {'name': 'ac_voltage', 'scale': 0.1, 'unit': 'V', 'desc': 'Grid voltage'}, |
| 532 | + 31109: {'name': 'ac_current', 'scale': 0.1, 'unit': 'A', 'desc': 'Grid current'}, |
| 533 | + |
| 534 | + # === Battery (cluster 1) === |
| 535 | + # Unsuffixed on purpose. The first-gen profile names these *_vpp to stop them |
| 536 | + # being used as fallbacks for its 3000-range battery registers. TL-XH2 has no |
| 537 | + # 3000 range, so these ARE the battery sensors — suffixing them here would |
| 538 | + # leave every battery entity empty. |
| 539 | + 31200: {'name': 'battery_power_high', 'scale': 1, 'unit': '', 'pair': 31201}, |
| 540 | + 31201: {'name': 'battery_power_low', 'scale': 1, 'unit': '', 'pair': 31200, |
| 541 | + 'combined_scale': 0.1, 'combined_unit': 'W', 'signed': True}, |
| 542 | + 31202: {'name': 'charge_energy_today_high', 'scale': 1, 'unit': '', 'pair': 31203}, |
| 543 | + 31203: {'name': 'charge_energy_today_low', 'scale': 1, 'unit': '', 'pair': 31202, |
| 544 | + 'combined_scale': 0.1, 'combined_unit': 'kWh'}, |
| 545 | + 31204: {'name': 'charge_power_high', 'scale': 1, 'unit': '', 'pair': 31205}, |
| 546 | + 31205: {'name': 'charge_power_low', 'scale': 1, 'unit': '', 'pair': 31204, |
| 547 | + 'combined_scale': 0.1, 'combined_unit': 'W', 'signed': True}, |
| 548 | + 31206: {'name': 'discharge_energy_today_high', 'scale': 1, 'unit': '', 'pair': 31207}, |
| 549 | + 31207: {'name': 'discharge_energy_today_low', 'scale': 1, 'unit': '', 'pair': 31206, |
| 550 | + 'combined_scale': 0.1, 'combined_unit': 'kWh'}, |
| 551 | + 31208: {'name': 'discharge_power_high', 'scale': 1, 'unit': '', 'pair': 31209}, |
| 552 | + 31209: {'name': 'discharge_power_low', 'scale': 1, 'unit': '', 'pair': 31208, |
| 553 | + 'combined_scale': 0.1, 'combined_unit': 'W', 'signed': True}, |
| 554 | + 31214: {'name': 'battery_voltage', 'scale': 0.1, 'unit': 'V', 'signed': True, |
| 555 | + 'desc': 'Battery voltage (verified against app, Issue #361)'}, |
| 556 | + 31215: {'name': 'battery_current', 'scale': 0.1, 'unit': 'A', 'signed': True, |
| 557 | + 'desc': 'Battery current'}, |
| 558 | + 31217: {'name': 'battery_soc', 'scale': 1, 'unit': '%', |
| 559 | + 'desc': 'Battery SOC (verified against app, Issue #361)'}, |
| 560 | + 31222: {'name': 'battery_temp', 'scale': 0.1, 'unit': '°C', 'signed': True, |
| 561 | + 'desc': 'Battery temperature'}, |
| 562 | + }, |
| 563 | + 'holding_registers': { |
| 564 | + **VPP_V201_HOLDING_1P, |
| 565 | + }, |
| 566 | +} |
| 567 | + |
461 | 568 | # Export all TL-XH profiles |
462 | 569 | TL_XH_REGISTER_MAPS = { |
463 | 570 | 'TL_XH_3000_10000': TL_XH_3000_10000, |
464 | 571 | 'TL_XH_US_3000_10000': TL_XH_US_3000_10000, |
465 | 572 | 'TL_XH_3000_10000_V201': TL_XH_3000_10000_V201, |
466 | 573 | 'TL_XH_US_3000_10000_V201': TL_XH_US_3000_10000_V201, |
467 | 574 | 'MIN_TL_XH_3000_10000_V201': MIN_TL_XH_3000_10000_V201, |
| 575 | + 'MIN_TL_XH2_3000_10000_V201': MIN_TL_XH2_3000_10000_V201, |
468 | 576 | } |
0 commit comments