Add supply frequency sensors to Tuya energy monitoring devices (#149320)

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
yufeng
2025-08-12 17:02:03 +08:00
committed by GitHub
parent 5b232226e9
commit fb4a452872
7 changed files with 609 additions and 0 deletions

View File

@@ -328,6 +328,7 @@ class DPCode(StrEnum):
STATUS = "status" STATUS = "status"
STERILIZATION = "sterilization" # Sterilization STERILIZATION = "sterilization" # Sterilization
SUCTION = "suction" SUCTION = "suction"
SUPPLY_FREQUENCY = "supply_frequency"
SWING = "swing" # Swing mode SWING = "swing" # Swing mode
SWITCH = "switch" # Switch SWITCH = "switch" # Switch
SWITCH_1 = "switch_1" # Switch 1 SWITCH_1 = "switch_1" # Switch 1

View File

@@ -363,6 +363,13 @@ SENSORS: dict[str, tuple[TuyaSensorEntityDescription, ...]] = {
device_class=SensorDeviceClass.ENERGY, device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING, state_class=SensorStateClass.TOTAL_INCREASING,
), ),
TuyaSensorEntityDescription(
key=DPCode.SUPPLY_FREQUENCY,
translation_key="supply_frequency",
device_class=SensorDeviceClass.FREQUENCY,
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT,
),
TuyaSensorEntityDescription( TuyaSensorEntityDescription(
key=DPCode.PHASE_A, key=DPCode.PHASE_A,
translation_key="phase_a_current", translation_key="phase_a_current",
@@ -1346,6 +1353,13 @@ SENSORS: dict[str, tuple[TuyaSensorEntityDescription, ...]] = {
complex_type=ElectricityTypeData, complex_type=ElectricityTypeData,
subkey="power", subkey="power",
), ),
TuyaSensorEntityDescription(
key=DPCode.SUPPLY_FREQUENCY,
translation_key="supply_frequency",
device_class=SensorDeviceClass.FREQUENCY,
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT,
),
TuyaSensorEntityDescription( TuyaSensorEntityDescription(
key=DPCode.PHASE_A, key=DPCode.PHASE_A,
translation_key="phase_a_current", translation_key="phase_a_current",

View File

@@ -743,6 +743,9 @@
}, },
"liquid_level": { "liquid_level": {
"name": "Liquid level" "name": "Liquid level"
},
"supply_frequency": {
"name": "Supply frequency"
} }
}, },
"switch": { "switch": {

View File

@@ -96,6 +96,7 @@ DEVICE_MOCKS = [
"dj_zav1pa32pyxray78", # https://github.com/home-assistant/core/issues/149704 "dj_zav1pa32pyxray78", # https://github.com/home-assistant/core/issues/149704
"dj_zputiamzanuk6yky", # https://github.com/home-assistant/core/issues/149704 "dj_zputiamzanuk6yky", # https://github.com/home-assistant/core/issues/149704
"dlq_0tnvg2xaisqdadcf", # https://github.com/home-assistant/core/issues/102769 "dlq_0tnvg2xaisqdadcf", # https://github.com/home-assistant/core/issues/102769
"dlq_cnpkf4xdmd9v49iq", # https://github.com/home-assistant/core/pull/149320
"dlq_jdj6ccklup7btq3a", # https://github.com/home-assistant/core/issues/143209 "dlq_jdj6ccklup7btq3a", # https://github.com/home-assistant/core/issues/143209
"dlq_kxdr6su0c55p7bbo", # https://github.com/home-assistant/core/issues/143499 "dlq_kxdr6su0c55p7bbo", # https://github.com/home-assistant/core/issues/143499
"dlq_r9kg2g1uhhyicycb", # https://github.com/home-assistant/core/issues/149650 "dlq_r9kg2g1uhhyicycb", # https://github.com/home-assistant/core/issues/149650

View File

@@ -0,0 +1,158 @@
{
"endpoint": "https://apigw.tuyacn.com",
"mqtt_connected": true,
"disabled_by": null,
"disabled_polling": false,
"name": "\u65ad\u8def\u5668HA",
"category": "dlq",
"product_id": "cnpkf4xdmd9v49iq",
"product_name": "Breaker",
"online": true,
"sub": false,
"time_zone": "+08:00",
"active_time": "2025-07-03T10:19:11+00:00",
"create_time": "2025-07-03T10:19:11+00:00",
"update_time": "2025-07-03T10:19:11+00:00",
"function": {
"switch": {
"type": "Boolean",
"value": {}
},
"alarm_set_1": {
"type": "Raw",
"value": {}
},
"alarm_set_2": {
"type": "Raw",
"value": {}
},
"leakagecurr_test": {
"type": "Boolean",
"value": {}
},
"online_state": {
"type": "Enum",
"value": {
"range": ["online", "offline"]
}
},
"child_lock": {
"type": "Boolean",
"value": {}
}
},
"status_range": {
"forward_energy_total": {
"type": "Integer",
"value": {
"unit": "kW\u00b7h",
"min": 0,
"max": 99999999,
"scale": 3,
"step": 1
}
},
"phase_a": {
"type": "Raw",
"value": {}
},
"fault": {
"type": "Bitmap",
"value": {
"label": [
"short_circuit_alarm",
"surge_alarm",
"overload_alarm",
"leakagecurr_alarm",
"temp_dif_fault",
"fire_alarm",
"high_power_alarm",
"self_test_alarm",
"ov_cr",
"unbalance_alarm",
"ov_vol",
"undervoltage_alarm",
"miss_phase_alarm",
"outage_alarm",
"magnetism_alarm",
"credit_alarm",
"no_balance_alarm",
"leakage_early_warning",
"overcur_early_warning",
"overvol_early_warning",
"overpow_early_warning",
"undvol_early_warning",
"higtemp_early_warning"
]
}
},
"leakage_current": {
"type": "Integer",
"value": {
"unit": "mA",
"min": 0,
"max": 1000,
"scale": 0,
"step": 1
}
},
"switch": {
"type": "Boolean",
"value": {}
},
"alarm_set_1": {
"type": "Raw",
"value": {}
},
"alarm_set_2": {
"type": "Raw",
"value": {}
},
"breaker_number": {
"type": "String",
"value": {
"maxlen": 255
}
},
"leakagecurr_test": {
"type": "Boolean",
"value": {}
},
"supply_frequency": {
"type": "Integer",
"value": {
"unit": "Hz",
"min": 0,
"max": 9999,
"scale": 2,
"step": 1
}
},
"online_state": {
"type": "Enum",
"value": {
"range": ["online", "offline"]
}
},
"child_lock": {
"type": "Boolean",
"value": {}
}
},
"status": {
"forward_energy_total": 120,
"phase_a": "Ag8JJQAASAAACAAAAAAACGME",
"fault": 0,
"leakage_current": 0,
"switch": false,
"alarm_set_1": "",
"alarm_set_2": "",
"breaker_number": "",
"leakagecurr_test": false,
"supply_frequency": 0,
"online_state": "online",
"child_lock": false
},
"set_up": true,
"support_local": true
}

View File

@@ -2818,6 +2818,230 @@
'state': '222.4', 'state': '222.4',
}) })
# --- # ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_current-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_current',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
'original_icon': None,
'original_name': 'Phase A current',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'phase_a_current',
'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_aelectriccurrent',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_current-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'current',
'friendly_name': '断路器HA Phase A current',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
}),
'context': <ANY>,
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_current',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '599.296',
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'original_icon': None,
'original_name': 'Phase A power',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'phase_a_power',
'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_apower',
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'power',
'friendly_name': '断路器HA Phase A power',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
}),
'context': <ANY>,
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '18.432',
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_voltage-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_voltage',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.VOLTAGE: 'voltage'>,
'original_icon': None,
'original_name': 'Phase A voltage',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'phase_a_voltage',
'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_avoltage',
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_voltage-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'voltage',
'friendly_name': '断路器HA Phase A voltage',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
}),
'context': <ANY>,
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_voltage',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '52.7',
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_supply_frequency-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.duan_lu_qi_ha_supply_frequency',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.FREQUENCY: 'frequency'>,
'original_icon': None,
'original_name': 'Supply frequency',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'supply_frequency',
'unique_id': 'tuya.qi94v9dmdx4fkpncqldsupply_frequency',
'unit_of_measurement': 'Hz',
})
# ---
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_supply_frequency-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'frequency',
'friendly_name': '断路器HA Supply frequency',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'Hz',
}),
'context': <ANY>,
'entity_id': 'sensor.duan_lu_qi_ha_supply_frequency',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_platform_setup_and_discovery[sensor.eau_chaude_current-entry] # name: test_platform_setup_and_discovery[sensor.eau_chaude_current-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
@@ -7641,6 +7865,62 @@
'state': '220.4', 'state': '220.4',
}) })
# --- # ---
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_supply_frequency-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.metering_3pn_wifi_stable_supply_frequency',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.FREQUENCY: 'frequency'>,
'original_icon': None,
'original_name': 'Supply frequency',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'supply_frequency',
'unique_id': 'tuya.obb7p55c0us6rdxkqldsupply_frequency',
'unit_of_measurement': 'Hz',
})
# ---
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_supply_frequency-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'frequency',
'friendly_name': 'Metering_3PN_WiFi_stable Supply frequency',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'Hz',
}),
'context': <ANY>,
'entity_id': 'sensor.metering_3pn_wifi_stable_supply_frequency',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '50.0',
})
# ---
# name: test_platform_setup_and_discovery[sensor.motion_sensor_lidl_zigbee_battery-entry] # name: test_platform_setup_and_discovery[sensor.motion_sensor_lidl_zigbee_battery-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
@@ -12542,6 +12822,62 @@
'state': '52.7', 'state': '52.7',
}) })
# --- # ---
# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_supply_frequency-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.xoca_dac212xc_v2_s1_supply_frequency',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.FREQUENCY: 'frequency'>,
'original_icon': None,
'original_name': 'Supply frequency',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'supply_frequency',
'unique_id': 'tuya.9oh1h1uyalfykgg4bdnzsupply_frequency',
'unit_of_measurement': 'Hz',
})
# ---
# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_supply_frequency-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'frequency',
'friendly_name': 'XOCA-DAC212XC V2-S1 Supply frequency',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'Hz',
}),
'context': <ANY>,
'entity_id': 'sensor.xoca_dac212xc_v2_s1_supply_frequency',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_total_energy-entry] # name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_total_energy-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({

View File

@@ -2565,6 +2565,102 @@
'state': 'on', 'state': 'on',
}) })
# --- # ---
# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_child_lock-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.duan_lu_qi_ha_child_lock',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Child lock',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'child_lock',
'unique_id': 'tuya.qi94v9dmdx4fkpncqldchild_lock',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_child_lock-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': '断路器HA Child lock',
}),
'context': <ANY>,
'entity_id': 'switch.duan_lu_qi_ha_child_lock',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_switch-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': None,
'entity_id': 'switch.duan_lu_qi_ha_switch',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Switch',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'switch',
'unique_id': 'tuya.qi94v9dmdx4fkpncqldswitch',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_switch-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': '断路器HA Switch',
}),
'context': <ANY>,
'entity_id': 'switch.duan_lu_qi_ha_switch',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_platform_setup_and_discovery[switch.eau_chaude_child_lock-entry] # name: test_platform_setup_and_discovery[switch.eau_chaude_child_lock-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({