Bonne idée, je viens de le faire.
Il y a un point que je n’arrive pas à comprendre.
Je ne connais pas le langage python, je découvre.
Dans plusieurs quirk je retrouve ce genre de définition :
def __init__(self, *args, **kwargs):
"""Init electrical measurement cluster."""
super().__init__(*args, **kwargs)
self.endpoint.device.power_bus.add_listener(self)
def power_reported(self, value):
"""Report consumption."""
self._update_attribute(self.POWER_L, value)
J’arrive pas à saisir… Qu’est que je dois mettre comme XXX_bus ?
Je sais pas si c’est la bonne piste, mais c’est histoire de comprendre aussi.
Merci d’avance
Finalement, après de nombreuses recherches, je bloque.
J’ai réussi un quirk en rajoutant simplement les 3 phases (ce qui m’intéressait le plus). Les 2 attributs de base sont remontés en entité, il n’y a aucune erreur au chargement.
Par contre, je ne trouve vraiment pas comment créer des entités spécifiques pour les attributs ajoutés.
Je rajouterai les autres attributs du cluster Owon histoire de finaliser, mais c’est dommage.
Le seul moyen de pouvoir s’en servir c’est zha toolkit. Mais au moins ça fonctionne.
Voila le quirk:
import logging
import zigpy.types as t
from typing import Dict
from zigpy.profiles import zha
from zigpy.quirks import CustomCluster, CustomDevice
from zigpy.zcl.foundation import ZCLAttributeDef, ZCLCommandDef
from zigpy.zcl.clusters.general import (
Basic,
Identify,
)
from zigpy.zcl.clusters.smartenergy import Metering
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
SKIP_CONFIGURATION,
)
_LOGGER = logging.getLogger(__name__)
class Owon_PC321_Simple_Metering(CustomCluster, Metering):
"""Owon PC321 CustomCluster .
Import all attributes but doesn't create entities.
Needs to use ZHA Toolkit to be usefull
"""
cluster_id = 0x0702
ep_attribute: str = "smartenergy_metering"
attributes = Metering.attributes.copy()
attributes.update(
{
0x2000: ("phase_A_power", t.uint24_t, True),
0x2001: ("phase_B_power", t.uint24_t, True),
0x2002: ("phase_C_power", t.uint24_t, True),
}
)
server_commands: dict[int, ZCLCommandDef] = {
0x20: ZCLCommandDef("get_history_record", {}, False, is_manufacturer_specific=True),
0x21: ZCLCommandDef("stop_sending_historical_record", {}, False, is_manufacturer_specific=True),
}
client_commands: dict[int, ZCLCommandDef] = {
0x20: ZCLCommandDef("sent_historical_record", {}, True, is_manufacturer_specific=True),
}
class Owon_OC321_Clear_Metering(CustomCluster):
cluster_id = 0xFFE0
ep_attribute = "clear_metering"
attributes: dict[int, ZCLAttributeDef] = {}
server_commands: dict[int, ZCLCommandDef] = {
0x00: ZCLCommandDef("clear_measurement_data", {}, is_manufacturer_specific=True),
}
client_commands: dict[int, ZCLCommandDef] = {}
""" New Device Owon PC321 """
class Owon_PC321(CustomDevice):
signature = {
#MODELS_INFO: [("Owon", "PC321")],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=13
# device_version=1
# input_clusters=[0, 3, 1794]
# output_clusters=[3]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.CONSUMPTION_AWARENESS_DEVICE,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Metering.cluster_id,
],
OUTPUT_CLUSTERS: [Identify.cluster_id],
},
},
"manufacturer": "OWON Technology Inc.",
}
replacement = {
#SKIP_CONFIGURATION: True,
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=83
# device_version=1
# input_clusters=[0, 3, 1794, 65504]
# output_clusters=[3]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.CONSUMPTION_AWARENESS_DEVICE,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Owon_PC321_Simple_Metering,
Owon_OC321_Clear_Metering,
],
OUTPUT_CLUSTERS: [Identify.cluster_id],
},
},
}
Pour ajouter les entités il faut maintenant modifier le code de l’intégration ZHA dans le core HA. Rien de simple donc.
Pour bien faire, il faut ajouter le quirk à la librairie ZHA device handler, puis une fois accepté, ouvrir un PR sur le core HA pour la création des entités. Ainsi tout le monde en profite.
Pour tester tu peux cloner le dossier ZHA et le mettre en custom component.
Le code à modifier est dans sensor.py :
J’ai moi-même ouvert un PR pour ajouter les entités à un programmateur d’arrosage mais j’y connais rien en test, du coup il végète :
Effectivement. Je pensais pouvoir faire ça directement dans le quirk mais non. C’est une modif à part.
J’ai créé 3 sensor (pour mes 3 phases) et une automatisation. Du coup, ça fonctionne de la même manière mais c’est un peu plus de travail.
Dès que j’ai un peu de temps je finalise avec tous les attributs et les sensors associés et je partage l’ensemble de mon code.
Je ferai aussi le PR, et je regarde du côté zha pour voir ce qui est faisable.
Voila finalement ce que j’ai réussi à faire.
Les entités ne sont pas créées automatiquement, il est nécessaire de le faire dans la configuration (j’ai mis le détail en commentaire).
Mais j’ai tout de même mes sensors et ils sont actualisés toutes les minutes.
Merci pour l’aide !!!
Voila le quirk :
""" QUIRK FOR OWON PC321 Z """
""" THIS QUIRK DOESN'T CREATE ENTITES WHEN THE DEVICE IS DISCOVERED """
""" TO MAKE IT RUNNING, YOU NEED TO CREATE SENSORS AND AN AUTOMATION. SEE CODE AT THE END """
import logging
import zigpy.types as t
from typing import Dict
from zigpy.profiles import zha
from zigpy.quirks import CustomCluster, CustomDevice
from zigpy.zcl.foundation import ZCLAttributeDef, ZCLCommandDef
from zigpy.zcl.clusters.general import (
Basic,
Identify,
)
from zigpy.zcl.clusters.smartenergy import Metering
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
SKIP_CONFIGURATION,
)
_LOGGER = logging.getLogger(__name__)
class Owon_PC321_Simple_Metering(CustomCluster, Metering):
""" Owon PC321 CustomCluster """
""" Import attributes but doesn't create entities """
""" Needs to use ZHA Toolkit to be usefull """
cluster_id = 0x0702
ep_attribute: str = "smartenergy_metering"
attributes = Metering.attributes.copy()
attributes.update(
{
0x2000: ("phase_A_power", t.uint24_t, True),
0x2001: ("phase_B_power", t.uint24_t, True),
0x2002: ("phase_C_power", t.uint24_t, True),
0x2100: ("phase_A_reactive_power", t.uint24_t, True),
0x2101: ("phase_B_reactive_power", t.uint24_t, True),
0x2102: ("phase_C_reactive_power", t.uint24_t, True),
0x2103: ("reactive_power_summation_of_the_3_phases", t.uint24_t, True),
0x3000: ("phase_A_voltage", t.uint24_t, True),
0x3001: ("phase_B_voltage", t.uint24_t, True),
0x3002: ("phase_C_voltage", t.uint24_t, True),
0x3100: ("phase_A_current", t.uint24_t, True),
0x3101: ("phase_B_current", t.uint24_t, True),
0x3102: ("phase_C_current", t.uint24_t, True),
0x3103: ("current_summation_of_the_3_phases", t.uint24_t, True),
0x3104: ("leakage_current", t.uint24_t, True),
0x4000: ("phase_A_energy_consumption", t.uint48_t, True),
0x4001: ("phase_B_energy_consumption", t.uint48_t, True),
0x4002: ("phase_C_energy_consumption", t.uint48_t, True),
0x4100: ("phase_A_reactive_energy_consumption", t.uint48_t, True),
0x4101: ("phase_B_reactive_energy_consumption", t.uint48_t, True),
0x4102: ("phase_C_reactive_energy_consumption", t.uint48_t, True),
0x4103: ("reactive_energy_summation_of_the_3_phases", t.uint48_t, True),
}
)
server_commands: dict[int, ZCLCommandDef] = {
0x20: ZCLCommandDef("get_history_record", {}, False, is_manufacturer_specific=True),
0x21: ZCLCommandDef("stop_sending_historical_record", {}, False, is_manufacturer_specific=True),
}
client_commands: dict[int, ZCLCommandDef] = {
0x20: ZCLCommandDef("sent_historical_record", {}, True, is_manufacturer_specific=True),
}
class Owon_OC321_Clear_Metering(CustomCluster):
cluster_id = 0xFFE0
ep_attribute = "clear_metering"
attributes: dict[int, ZCLAttributeDef] = {}
server_commands: dict[int, ZCLCommandDef] = {
0x00: ZCLCommandDef("clear_measurement_data", {}, is_manufacturer_specific=True),
}
client_commands: dict[int, ZCLCommandDef] = {}
""" New Device Owon PC321 Z """
class Owon_PC321(CustomDevice):
signature = {
#MODELS_INFO: [("Owon", "PC321")],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=13
# device_version=1
# input_clusters=[0, 3, 1794]
# output_clusters=[3]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.CONSUMPTION_AWARENESS_DEVICE,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Metering.cluster_id,
],
OUTPUT_CLUSTERS: [Identify.cluster_id],
},
},
"manufacturer": "OWON Technology Inc.",
}
replacement = {
#SKIP_CONFIGURATION: True,
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=83
# device_version=1
# input_clusters=[0, 3, 1794, 65504]
# output_clusters=[3]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.CONSUMPTION_AWARENESS_DEVICE,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Owon_PC321_Simple_Metering,
Owon_OC321_Clear_Metering,
],
OUTPUT_CLUSTERS: [Identify.cluster_id],
},
},
}
""" REPORTING """
""" TO HAVE ENTIIES REPORTING IT IS NEEDED TO CREATE SENSORS """
""" COPY THE FOLLOWING. DATAS ARE COPIE 'AS IS'. TO HAVE WELL FORMATTED DATAS, SEE BELOW """
"""
template:
- sensor:
- name: owon_power_phase_A
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_power_phase_B
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_power_phase_C
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_power_phase_A
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_power_phase_B
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_power_phase_C
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_power_summation_of_the_3_phases
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_voltage_phase_A_brut
unit_of_measurement: "dV"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_voltage_phase_B_brut
unit_of_measurement: "dV"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_voltage_phase_C_brut
unit_of_measurement: "dV"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_current_phase_A_brut
unit_of_measurement: "mA"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_current_phase_B_brut
unit_of_measurement: "mA"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_current_phase_C_brut
unit_of_measurement: "mA"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_current_summation_of_the_3_phases_brut
unit_of_measurement: "mA"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_leakage_current
unit_of_measurement: "A"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_energy_consumption_phase_A
unit_of_measurement: "kWh"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_energy_consumption_phase_B
unit_of_measurement: "kWh"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_energy_consumption_phase_C
unit_of_measurement: "kWh"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_energy_consumption_phase_A
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_energy_consumption_phase_B
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_energy_consumption_phase_C
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
- name: owon_reactive_energy_summation_of_the_3_phases
unit_of_measurement: "W"
device_class: energy
state_class: total_increasing
state: 0
"""
""" TO HAVE ENTIIES WELL FOMATTED, IT IS NEEDED TO CREATE FOLLOWING SENSORS """
"""
- platform: template
sensors:
owon_voltage_phase_a:
unit_of_measurement: 'V'
value_template: "{{ (states('sensor.owon_voltage_phase_a_brut') | int / 10 | round(1)) }}"
device_class: energy
owon_voltage_phase_b:
unit_of_measurement: 'V'
value_template: "{{ (states('sensor.owon_voltage_phase_b_brut') | int / 10 | round(1)) }}"
device_class: energy
owon_voltage_phase_c:
unit_of_measurement: 'V'
value_template: "{{ (states('sensor.owon_voltage_phase_c_brut') | int / 10 | round(1)) }}"
device_class: energy
owon_current_phase_a:
unit_of_measurement: 'A'
value_template: "{{ (states('sensor.owon_current_phase_a_brut') | int / 1000 | round(1)) }}"
device_class: energy
owon_current_phase_b:
unit_of_measurement: A
value_template: "{{ (states('sensor.owon_current_phase_b_brut') | int / 1000 | round(1)) }}"
device_class: energy
owon_current_phase_c:
unit_of_measurement: 'A'
value_template: "{{ (states('sensor.owon_current_phase_c_brut') | int / 1000 | round(1)) }}"
device_class: energy
"""
""" TO UPDATE THESE SENSORS AUTOMATICALLY """
""" CREATE A NEW AUTOMATION AND COPY THE FOLLOWING. UPDATE IS EVERY MINUTE """
"""
alias: Owon PC321
description: Lecture Owon PC321 every minute
trigger:
- platform: time_pattern
hours: "*"
minutes: /1
seconds: "0"
condition: []
action:
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
state_id: sensor.owon_power_phase_A
allow_create: false
attribute: 8192
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 8193
state_id: sensor.owon_power_phase_B
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 8194
state_id: sensor.owon_power_phase_C
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 8448
state_id: sensor.owon_reactive_power_phase_A
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 8449
state_id: sensor.owon_reactive_power_phase_B
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 8450
state_id: sensor.owon_reactive_power_phase_C
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 8451
state_id: sensor.owon_reactive_power_summation_of_the_3_phases
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12288
state_id: sensor.owon_voltage_phase_A_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12289
state_id: sensor.owon_voltage_phase_B_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12290
state_id: sensor.owon_voltage_phase_C_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12544
state_id: sensor.owon_current_phase_A_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12545
state_id: sensor.owon_current_phase_B_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12546
state_id: sensor.owon_current_phase_C_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12547
state_id: sensor.owon_current_summation_of_the_3_phases_brut
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 12549
state_id: sensor.owon_leakage_current
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16384
state_id: sensor.owon_energy_consumption_phase_A
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16385
state_id: sensor.owon_energy_consumption_phase_B
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16386
state_id: sensor.owon_energy_consumption_phase_C
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16640
state_id: sensor.owon_reactive_energy_consumption_phase_A
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16641
state_id: sensor.owon_reactive_energy_consumption_phase_B
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16642
state_id: sensor.owon_reactive_energy_consumption_phase_C
allow_create: false
- service: zha_toolkit.execute
data:
command: attr_read
ieee: 3c:6a:2c:ff:fe:d2:ef:73
cluster: 1794
attribute: 16643
state_id: sensor.owon_reactive_energy_summation_of_the_3_phases
allow_create: false
mode: single
"""
Je suis en train de regarder pour faire une modif.
Côté zha ça va, je comprends un peu le fonctionnement.
Mais pour faire les choses bien, j’aimerais bien créer un nouveau cluster dans zigpy.zcl.clusters. Pour faire appel non pas à Metering, mais un nouveau dédié à l’équipement.
Est-ce qu’il y a aussi une possibilité de cloner ce dossier aussi ? J’ai cherché mais je ne trouve rien.