ZHA display of AnalogIn values

(I’m not getting any responses to my previous question - Zigbee device shows attributes but no controls in HA - Configuration / Zigbee - Home Assistant Community (home-assistant.io) - so I’ trying a different approach)

Using ZHA with a fully updated HA, and an ESP32-H2 with the latest IDF-SDK I’m trying to create a very basic Zigbee end device that can send data to the HA.

Using the Espressif example code to turn the LED on the ESP32-H2 on and off, I can connect the end device and the Zigbee HA ‘Device’ window shows a switch that I can toggle to turn the end device LED on and off.

What I can’t do is to create an ‘AnalogIn’ cluster in the end device that shows up as a numeric display on HA. I get to the point where the ‘Manage Device’ window shows the attribute and I can see the value the end device is sending, but I can’t get that value displayed in the device web page.

What am I missing (probably a lot!)?

Susan

Can you please use the states menu in developer-tools (in HA) to show us the state and attributes?

Assuming you already know that the ZHA integration will need a custom ZHA Device Handler (a.k.a. “quirk”) and perhaps even extend ZHA’s sensor or number code in Home Assistant’s core (zha component) if you want to expose clusters and attributes sensors or numbers as entities in the ZHA UI that are not considered standard or have not been previously added to the zha component, read and see:

https://www.home-assistant.io/integrations/zha#how-to-add-support-for-new-and-unsupported-devices

and

https://github.com/zigpy/zha-device-handlers/blob/aeca76da0ea81ecba5b17e0f7314620cd686faae/README.md

and

https://github.com/home-assistant/core/tree/dev/homeassistant/components/zha

Probably best if you post your questions to ZHA Device Handlers and/or zigpy’s repositories on GitHub for the attention of zigpy/zha/quirks developers to notice and discuss there (ZHA and zigpy developers usually don’t post in this community forum):

https://github.com/zigpy/zha-device-handlers/discussions

https://github.com/zigpy/zigpy

You could also try posting issues to esp-zigbee-sdk repo too for Espressif’s devs attention as well:

@nickrout - the only entity that is shown there is:


The ‘Signature’ is:

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.MainsPowered|RxOnWhenIdle|AllocateAddress: 140>, manufacturer_code=4660, maximum_buffer_size=108, maximum_incoming_transfer_size=0, server_mask=11264, maximum_outgoing_transfer_size=0, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=False, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0002",
      "input_clusters": [
        "0x0000",
        "0x0006"
      ],
      "output_clusters": []
    },
    "2": {
      "profile_id": "0x0104",
      "device_type": "0x0007",
      "input_clusters": [
        "0x000c"
      ],
      "output_clusters": [
        "0x000d"
      ]
    }
  },
  "manufacturer": "ConMac",
  "model": "Weather2",
  "class": "zigpy.device.Device"
}

@Hedda: I have tried to write a quirk:

""" Custom quirk for the ConMac Weather2 zigbee device"""
from zigpy.profiles import zha

from zigpy.quirks import CustomDevice

from zhaquirks.const import 
{
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
}

from zigpy.zcl.clusters.general import
{
    AnalogInput,
    AnalogOutput,
    Basic,
    OnOff,
}

# class AnalogInputCluster( CustomCluster, AnalogInput):
#     cluster_id = AnalogInput.cluster_id
#     def __init__(self,*args, **kwargs):
#         self.current_state = {}
#         super().__init__(*args, **kwargs)
        
#     def _update_attribute( self, attrid, value):
#         super()._update_attribute( attrid, value)
#         if value is not None and value >= 0:
#             self.endpoint.device.power_bus.listener_even(POWER_REPORTED, value)

class ConMacWeather2( CustomDevice):
    
    def __init__(self. *args, **kwargs):
        """Init,"""
        super().__init__(*args, **kwargs)
    
    signature = {
        MODELS_INFO: [("Weather2", "manuforte.org")],
        ENDPOINTS: {
            # < SimpleDescriptor endpoint=2 profile=0x0104 device_type=0x0002
            # device_version=1
            # input_clusters=[0,6]
            # output_clusters=[]>
            1: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0002,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    OnOff.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            # < SimpleDescriptor endpoint=2 profile=0x0104 device_type=0x0007
            # device_version=1
            # input_clusters=[12]
            # output_clusters=[13]>
            2: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0007,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    AnalogOutput.cluster_id,
                ],
            },
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0002,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    OnOff.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
               },
            2: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0007,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    AnalogOutput.cluster_id,
                ],
               },
           },
        "manufacturer": "ConMac",
        "model": "Weather2",
    }

and also have the following in my ‘configurations.yaml’ file:


zha:
  enable_quirks: true
  custom_quirks_path: /config/custom_zha_quirks/
  database_path: /config/zigbee.db

What concerns me about that is that the log created while connecting my end device contains:

Checking quirks for ConMac Weather2 (48:31:b7:ff:fe:c0:71:27)
Considering <class 'zhaquirks.xiaomi.aqara.opple_switch.XiaomiOpple2ButtonSwitchFace2'>
Fail because endpoint list mismatch: {1, 2, 242} {1, 2}
Considering <class 'zhaquirks.xiaomi.aqara.opple_switch.XiaomiOpple2ButtonSwitchFace1'>
Fail because endpoint list mismatch: {1, 2, 41, 42, 242, 51, 21, 31} {1, 2}
Considering <class 'zhaquirks.xbee.xbee_io.XBeeSensor'>
Fail because endpoint list mismatch: {232, 230} {1, 2}
Considering <class 'zhaquirks.xbee.xbee3_io.XBee3Sensor'>
Fail because endpoint list mismatch: {232, 230} {1, 2}
Considering <class 'zhaquirks.tuya.ts0201.MoesTemperatureHumidtySensorWithScreen'>
Fail because endpoint list mismatch: {1} {1, 2}
Considering <class 'zhaquirks.smartthings.tag_v4.SmartThingsTagV4'>
Fail because endpoint list mismatch: {1} {1, 2}
Considering <class 'zhaquirks.smartthings.multi.SmartthingsMultiPurposeSensor'>
Fail because endpoint list mismatch: {1} {1, 2}
Considering <class 'zhaquirks.netvox.z308e3ed.Z308E3ED'>
Fail because endpoint list mismatch: {1} {1, 2}
Considering <class 'zhaquirks.gledopto.soposhgu10.SoposhGU10'>
Fail because endpoint list mismatch: {11, 13} {1, 2}
Creating cluster handler for cluster id: 0 class: <class 'homeassistant.components.zha.core.cluster_handlers.general.BasicClusterHandler'>

which make me think that my quirk is not even being checked.
Susan

@AussieSusan Even if you are trying to write quirks yourself I still suggest that you also create a new “Device support request” as an issue on the ZHA Device Handlers repository on GitHub to start a dialogue there with other ZHA quirk developers as you are much more likley to get better and more expert feedback there than here in the Home Assistant community forums → https://github.com/zigpy/zha-device-handlers/issues/new/choose

PS: I written a small step-by-step guide for how-to add custom quirks here (though it does not cover all set-up scenarios) → Add a how-to guide for how end-users can use a custom quirk in ZHA by Hedda · Pull Request #2419 · zigpy/zha-device-handlers · GitHub

Thanks @Hedda. I had seen those links before (but I must be dumb - I’ve searched all around the page you link to but I can’t see the actual document with your ‘step-by-step’ guide.) Is there a direct link to the document?

I’m reluctant to create a new Device Support Request because I’m just trying to get a simply “example” system set up - what I want to end up with is an end device that has multiple analog and binary inputs and a few controlling outputs. Once I get the simple case to work, then I can extend it to what I want. Therefore I don’t want to waste anyone’s time by creating a device support request for something that will never go anywhere.
Susan

It is not a document but a not yet merged pull request with an update for the readme.md for the ZHA Device Handlers project on GitHu, however you can view the change or the updated file from that PR here:

https://github.com/zigpy/zha-device-handlers/pull/2419/commits/ed20dbf43375b3b01fca2567dbd4647dd629d936

https://github.com/zigpy/zha-device-handlers/blob/ed20dbf43375b3b01fca2567dbd4647dd629d936/README.md#how-end-users-can-test-a-not-yet-merged-custom-quirk-in-zha

If you do not want to submit a formal Device Support Request (which I would argue is still probably the best approach to get the attention and feedback from experts and more experienced contributors) then suggest you create new discussions to the ZHA Device Handlers and/or zigpy projects (though note there are not as much activity in those discussions boards compares to Device Support Request issues):

https://github.com/zigpy/zha-device-handlers/discussions

and/or

https://github.com/zigpy/zigpy/discussions

Tip is to at least make sure that any subject titles are very clear and have details to get right attention.

Just to close this off - I have the first step working.
There were syntax errors in my quirk and I only found where these were logged recently.
Also, the examples shown at zigpy/zha-device-handlers: ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices. (github.com) contain references to “MODELS_INFO:” and “SKIP_CONFIGURATION:” which were flagged as errors - the names were undefined - in my simple ‘pass through’ quirk (in my post fo the 5th of December 2023).
Now I can move on to get the analog values shown in the UI but at least I now have a stable quirk to build from.
Thanks all (especially @Hedda).
Susan

1 Like

Suggest that you edit you submit one or more improvement pull requests with changes to their readme.md if the suspect can be helpful for others → https://github.com/zigpy/zha-device-handlers/blob/a0c41091e857bd28a070b96dc065f2fe29f08539/README.md

It is a community project so need help from community to improve :wink:

Sorry to jump into this discussion but I have just received two ESP32-H2 dev boards and have managed to get the simple light/switch example working. My next step is to try and get one of the board to connect to HA via my SkyConnect USB. Forgive my lack of knowledge but it looks like I need to provide a “quirk” to HA so it is aware of the esp32-h2 device. Could anyone provide a pointer as how I can do this and the details required to enable connection of my esp32-h2 board to HA. Do i need to make any changes on esp32-h2 side or should the light example code work as is?

Many thanks,

Pete.

My experience is that the Espressif ‘HA_on_off_light’ example works well with the SkyConnect USB via the ‘Zigbee Home Automation’ (ZHA) integration.
It doesn’t need a custom quirk to work with the switch in HA turning the LED on the ESP32-H2 on and off.
I did write a quirk that was, in effect, a ‘noop’ (i.e. the ‘signature’ and ‘replacement’ parts are identical and looking at the ZHA log while the end device is being interviewed etc. I can see that it was picked up. The reason I say it is a ‘noop’ ia that this part works as well if the custom quirk is not there.
HOWEVER, my next step was to add a temperature measurement cluster (that I also put into the custom quirk as a ‘noop’) and I can also see that the temperature sensor shows in the ZHA UI for the device but I cannot get the value to be updated (see my other - unanswered - posting at Not updating value in UI).
Susan

FWIW, my quirk is:

""" Custom quirk for the ConMac Weather2 zigbee device"""
from zigpy.profiles import zha

from zigpy.quirks import CustomDevice

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)

from zigpy.zcl.clusters.general import (
#    AnalogInput,
#    AnalogOutput,
    Basic,
    OnOff,
)

from zigpy.zcl.clusters.measurement import (
    TemperatureMeasurement,
)

# class AnalogInputCluster( CustomCluster, AnalogInput):
#     cluster_id = AnalogInput.cluster_id
#     def __init__(self,*args, **kwargs):
#         self.current_state = {}
#         super().__init__(*args, **kwargs)
        
#     def _update_attribute( self, attrid, value):
#         super()._update_attribute( attrid, value)
#         if value is not None and value >= 0:
#             self.endpoint.device.power_bus.listener_even(POWER_REPORTED, value)

class ConMacWeather2( CustomDevice):
    
    def __init__(self, *args, **kwargs):
        """Init,"""
        super().__init__(*args, **kwargs)
    
    signature = {
#        MODELS_INFO: [("Weather2", "manuforte.org")],
        ENDPOINTS: {
            # < SimpleDescriptor endpoint=2 profile=0x0104 device_type=0x0002
            # device_version=1
            # input_clusters=[0,6]
            # output_clusters=[]>
            1: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0002,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    OnOff.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            # < SimpleDescriptor endpoint=2 profile=0x0104 device_type=0x0007
            # device_version=1
            # input_clusters=[12]
            # output_clusters=[13]>
            2: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0302,
                INPUT_CLUSTERS: [
                    TemperatureMeasurement.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
        },
    }
    replacement = {
#        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0002,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    OnOff.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
               },
            2: {
                PROFILE_ID: 0x0104,
                DEVICE_TYPE: 0x0302,
                INPUT_CLUSTERS: [
                    TemperatureMeasurement.cluster_id
                ],
                OUTPUT_CLUSTERS: [],
               },
           },
        "manufacturer": "ConMac",
        "model": "Weather2",
    }

It is pretty much as the example quirks are but note the commented out ‘MODELS_INFO’ and ‘SKI{_CONFIGURAITON’ lines which cause errors. Also ignore the references to ‘AnalogIn’ - that was my first attempt before switching to the Temperature Measurement cluster.

Thank you for your quick reply. Just to confirm I understand your response. With the current version of HA, ZHA and SkyConnect. If I compile and flash an ESP32-H2 with the example code within idf (HA_on_off_light) I should be able to connect it to my existing network (no changes necessary)? I try “add devices” within ZHA, reboot the esp32 (boot button) and get the following (last two lines of code).

I (401) ESP_ZB_ON_OFF_LIGHT: ZDO signal: ZDO Config Ready (0x17), status: ESP_FAIL
I (401) ESP_ZB_ON_OFF_LIGHT: Zigbee stack initialized
W (8591) ESP_ZB_ON_OFF_LIGHT: Failed to initialize Zigbee stack (status: ESP_FAIL)

Thanks again.
I must be doing something wrong, the SkyConnect and ESP are about 1m apart.

Finally. I now have it connected.

Screenshot from 2024-01-01 11-23-21

My network must be a bit flaky…

Pete.

Make sure that the SkyConnect dongle is away from USB3 sockets and also (as I found out) from other WiFi devices as they seen to swamp the dongle.
BTW I also get the ‘failed to initialize ZIgbee stack’ message and a few others as well but generally the stack recovers by itself.
I’ve also noticed that erasing the flash (i.e the NVM in the ESP32-H2 using the ‘erase-flash’ argument to idf.py) will slow down the reconnection to the coordinator unless the coordinator removes the old device entry and you create a new one. If you just flash the new program and let it keep the same PAN ID etc. then it will reconnect by itself (eventually).
Susan

@Hedda - I have submitted an ‘Issue’ to the GitHub issues list - #2881 - a month ago and no response at all. Is this typical? (I note that there are 371 open issues and you have to go back about 225 issues to find a page that does not have issues that have no response.)
Susan

It is a community of volenteers (not a company with paid employees) working on ZHA Device Handlers / quirks so make sure use clear and interesting subject title + post all details requested and more, but yeah, if you post about a DIY device that no one else has then better make it very interesting or else it might not be replied to as it is not like a commercial product that others have also bought.

That is, if you are using a device that no one else is using then you not only need to do a good job att explaining what you are doing and how, you also need to see if you can dig into the device handler code yourself and try making a quirk so others can help you make it instead of you helping them make it.

If it is a DIY device then maybe a glood idea to also post in other channels and other communities, like example the Home Assistant Discord server, and zigpy discussions → zigpy/zigpy · Discussions · GitHub

Maybe also test with Zigbee2MQTT and post in their community dicussions to on GitHub → Koenkk/zigbee2mqtt · Discussions · GitHub

Hello Susan,

I am trying to do something very similar using the esp32 h2. Can you provide your code on the esp32 h2?

Here is my code. It is basically the esp ‘HA_on_off_light’ that I have modified a bit.

/*
 * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: LicenseRef-Included
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Espressif Systems
 *    integrated circuit in a product or a software update for such product,
 *    must reproduce the above copyright notice, this list of conditions and
 *    the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * 4. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_check.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "ha/esp_zigbee_ha_standard.h"
#include "esp_zb_light.h"

#include "esp_adc/adc_oneshot.h"



/**
 * @note Make sure set idf.py menuconfig in zigbee component as zigbee end device!
*/
#if !defined ZB_ED_ROLE
#error Define ZB_ED_ROLE in idf.py menuconfig to compile light (End Device) source code.
#endif

static const char *TAG = "ESP_ZB_ON_OFF_LIGHT";

// static int adc_raw[2][10];

static int network_active = 0;

static int16_t counter = 0;
static int16_t humidity = 5000;
static int16_t rel_pressure = 1016;

static esp_zb_temperature_meas_cluster_cfg_t temperature_cfg;
static esp_zb_humidity_meas_cluster_cfg_t humidity_cfg;
static esp_zb_pressure_meas_cluster_cfg_t pressure_cfg;
static esp_zb_analog_input_cluster_cfg_t analog_input_cfg;


/********************* Define functions **************************/
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask)
{
    ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask));
}


static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message)
{
    esp_err_t ret = ESP_OK;
    bool light_state = 0;

    ESP_RETURN_ON_FALSE(message, ESP_FAIL, TAG, "Empty message");
    ESP_RETURN_ON_FALSE(message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS, ESP_ERR_INVALID_ARG, TAG, "Received message: error status(%d)",
                        message->info.status);
    ESP_LOGI(TAG, "Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", message->info.dst_endpoint, message->info.cluster,
             message->attribute.id, message->attribute.data.size);
    if (message->info.dst_endpoint == HA_ESP_LIGHT_ENDPOINT) {
        if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
            if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
                light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state;
                ESP_LOGI(TAG, "Light set to %s", light_state ? "On" : "Off");
                light_driver_set_power(light_state);
            }
        }
    }
    return ret;
}


static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message)
{
    esp_err_t ret = ESP_OK;
    switch (callback_id) {
    case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID:
        ret = zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)message);
        break;
    case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID:
        {
            esp_zb_zcl_cmd_default_resp_message_t *msg = (esp_zb_zcl_cmd_default_resp_message_t*)message;
            ESP_LOGI(TAG, "Default Response: Status: 0x%04x, Command: %d", msg->status_code, msg->resp_to_cmd);
            ESP_LOGI(TAG, "   Src addr: 0x%04x, Dst Addr: 0x%04x, src ep: %d, dst ep: %d, cluster: 0x%04x, profile: 0x%04x",
                        msg->info.src_address.u.short_addr, msg->info.dst_address, msg->info.src_endpoint, msg->info.dst_endpoint,
                        msg->info.cluster, msg->info.profile);
            ESP_LOGI(TAG, "   Resp status: 0x%04x, frame control: 0x%02x, mfg code: 0x%04x, txn: %d, RSSI: %d",
                        msg->info.status, msg->info.header.fc, msg->info.header.manuf_code, msg->info.header.tsn, msg->info.header.rssi);
            ret = ESP_OK;
        }
        break;
    default:
        ESP_LOGW(TAG, "Receive Zigbee action(0x%x) callback", callback_id);
        break;
    }
    return ret;
}


void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
{
    uint32_t *p_sg_p       = signal_struct->p_app_signal;
    esp_err_t err_status = signal_struct->esp_err_status;
    esp_zb_app_signal_type_t sig_type = *p_sg_p;
    esp_zb_zdo_signal_leave_params_t *leave_params = NULL;

    switch (sig_type) {
    case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
        ESP_LOGI(TAG, "Zigbee stack initialized");
        esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
        break;

    case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START:
    case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT:
        if( sig_type == ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START)
        { ESP_LOGI(TAG, "First Start"); }
        else
        { ESP_LOGI(TAG, "Restart"); }
        network_active = 0;
        if (err_status == ESP_OK) {
            ESP_LOGI(TAG, "Start network steering");
            esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
        } else {
            /* commissioning failed */
            ESP_LOGW(TAG, "Failed to initialize Zigbee stack (status: %d)", err_status);
//            esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
            esp_zb_scheduler_alarm(( esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
        }
        break;

    case ESP_ZB_BDB_SIGNAL_STEERING:
        if (err_status == ESP_OK) {
            esp_zb_ieee_addr_t extended_pan_id;
            esp_zb_get_extended_pan_id(extended_pan_id);
            ESP_LOGI(TAG, "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d)",
                     extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4],
                     extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0],
                     esp_zb_get_pan_id(), esp_zb_get_current_channel());
            network_active = 1;

        } else {
            ESP_LOGI(TAG, "Network steering was not successful (status: %d)", err_status);
            esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
            network_active = 0;
        }
        break;

    case ESP_ZB_ZDO_SIGNAL_LEAVE:
        {
            network_active = 0;
            leave_params = (esp_zb_zdo_signal_leave_params_t*)esp_zb_app_signal_get_params(p_sg_p);
            if( leave_params->leave_type == ESP_ZB_NWK_LEAVE_TYPE_RESET)
            {
                ESP_LOGI(TAG, "Reset Device");
                esp_zb_factory_reset();
            }
            else
            {
                ESP_LOGI( TAG, "Leave Signal Received - Status : %d", err_status);
            }
        }
        break;

    case ESP_ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
        ESP_LOGI( TAG, "Production Config Ready - Status : %d", err_status);
        break;

    case ESP_ZB_ZDO_DEVICE_UNAVAILABLE:
        ESP_LOGW( TAG, "Device Unavailable - Status: %d", err_status);
        network_active = 0;
        break;

    case ESP_ZB_NLME_STATUS_INDICATION:
        ESP_LOGI( TAG, "NLME Status Indication - Status: %d", err_status);
        ESP_LOGI(TAG, "...sig-type: %s, p_sg_p: 0x%x", esp_zb_zdo_signal_to_string(sig_type),
                    *(uint8_t*)esp_zb_app_signal_get_params(p_sg_p)); 
        break;

    default:
        ESP_LOGI(TAG, "ZDO signal: %d, status: %d", sig_type, err_status);
        break;
    }
}


static void esp_zb_task(void *pvParameters)
{
    char model_id[10] = "\x08" "Weather2";
    char manufacturer_id[10] = "\x06" "ConMac";
    uint8_t zcl_version  = 8;
    uint8_t power_source = 4;

    ESP_LOGI(TAG, "Starting configuration");

    /* initialize Zigbee stack with Zigbee end-device config */
    esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG();
    esp_zb_init(&zb_nwk_cfg);

    esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();

    esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_zcl_attr_list_create( ESP_ZB_ZCL_CLUSTER_ID_BASIC);
    esp_zb_basic_cluster_add_attr( esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, model_id);
    esp_zb_basic_cluster_add_attr( esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, manufacturer_id);
    esp_zb_basic_cluster_add_attr( esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_ZCL_VERSION_ID, &zcl_version);
    esp_zb_basic_cluster_add_attr( esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &power_source);
    esp_zb_cluster_list_add_basic_cluster( esp_zb_cluster_list, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);


    esp_zb_on_off_cluster_cfg_t on_off_cfg;
    on_off_cfg.on_off = ESP_ZB_ZCL_ON_OFF_ON_OFF_DEFAULT_VALUE;
    esp_zb_attribute_list_t *esp_zb_on_off_cluster = esp_zb_on_off_cluster_create( &on_off_cfg);
    esp_zb_cluster_list_add_on_off_cluster( esp_zb_cluster_list, esp_zb_on_off_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    esp_zb_cluster_list_t *esp_zb_cluster_list2 = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_basic_cluster( esp_zb_cluster_list2, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    temperature_cfg.max_value = 10000;
    temperature_cfg.min_value = -2000;
    temperature_cfg.measured_value = 1850;
    esp_zb_attribute_list_t *temperature_cluster = esp_zb_temperature_meas_cluster_create( &temperature_cfg);
    esp_zb_cluster_list_add_temperature_meas_cluster( esp_zb_cluster_list2, temperature_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);


    humidity_cfg.max_value = 10000;
    humidity_cfg.min_value = 0;
    humidity_cfg.measured_value = 5000;
    esp_zb_attribute_list_t *humidity_cluster = esp_zb_humidity_meas_cluster_create(&humidity_cfg);
    esp_zb_cluster_list_add_humidity_meas_cluster( esp_zb_cluster_list2, humidity_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);


    ESP_LOGI( TAG, "Adding pressure cluster");
    pressure_cfg.max_value = 1100;
    pressure_cfg.min_value =  900;
    pressure_cfg.measured_value = 1013;
    int16_t scaledValue = 10132;
    int16_t minScaledValue =  9000;
    int16_t maxScaledValue = 11000;
    int8_t  scale = 1;
    esp_zb_attribute_list_t *pressure_attr_list = esp_zb_pressure_meas_cluster_create(&pressure_cfg);
    ESP_LOGI( TAG, "Extending pressure cluster");
    esp_zb_cluster_add_attr( pressure_attr_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, 0x0010, 
                    ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY, &scaledValue);
    esp_zb_cluster_add_attr( pressure_attr_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, 0x0011, 
                    ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY, &minScaledValue);
    esp_zb_cluster_add_attr( pressure_attr_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, 0x0012, 
                    ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY, &maxScaledValue);
    esp_zb_cluster_add_attr( pressure_attr_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, 0x0014, 
                    ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY, &scale);
    ESP_LOGI( TAG, "Adding pressure cluster");
    esp_zb_cluster_list_add_pressure_meas_cluster(esp_zb_cluster_list2, pressure_attr_list, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
    ESP_LOGI( TAG, "Pressure Cluster Added");


    analog_input_cfg.status_flags = 0;
    analog_input_cfg.out_of_service = false;
    analog_input_cfg.present_value = 123.4;
    esp_zb_attribute_list_t *analog_cluster = esp_zb_analog_input_cluster_create(&analog_input_cfg);
    esp_zb_cluster_list_add_analog_input_cluster( esp_zb_cluster_list2, analog_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);


    esp_zb_ep_list_t *esp_zb_ep_list = esp_zb_ep_list_create();
    esp_zb_ep_list_add_ep( esp_zb_ep_list, esp_zb_cluster_list, HA_ESP_LIGHT_ENDPOINT, 
                           ESP_ZB_AF_HA_PROFILE_ID, ESP_ZB_HA_ON_OFF_OUTPUT_DEVICE_ID);
    esp_zb_ep_list_add_ep( esp_zb_ep_list, esp_zb_cluster_list2, HA_ESP_TEMPERATURE_ENDPOINT, 
                           ESP_ZB_AF_HA_PROFILE_ID, ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID);


    esp_zb_device_register( esp_zb_ep_list);

    esp_zb_core_action_handler_register( zb_action_handler);

    esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK);
    ESP_ERROR_CHECK(esp_zb_start(false));

    // Start the stack working
    esp_zb_main_loop_iteration();
}

static void adc_task(  void *pvParameters)
{
    // adc_oneshot_unit_handle_t adc_handle;
    // adc_oneshot_unit_init_cfg_t adc_cfg =
    // {
    //     .unit_id = ADC_UNIT_1,
    //     .ulp_mode = ADC_ULP_MODE_DISABLE,
    // };
    // ESP_ERROR_CHECK( adc_oneshot_new_unit( &adc_cfg, &adc_handle));
    // adc_oneshot_chan_cfg_t config =
    // {
    //     .bitwidth = ADC_BITWIDTH_DEFAULT,
    //     .atten = ADC_ATTEN_DB_12,
    // };
    // ESP_ERROR_CHECK( adc_oneshot_config_channel( adc_handle, ADC_CHANNEL_0, &config));

    while(1)
    {
        
        if( network_active)
        {
            // ESP_ERROR_CHECK( adc_oneshot_read( adc_handle, ADC_CHANNEL_0, &adc_raw[0][0]));
            // ESP_LOGI( TAG, "ADC1 Channel 0 = %04x", adc_raw[0][0]);

            esp_zb_zcl_status_t status;
            status = esp_zb_zcl_set_attribute_val( HA_ESP_TEMPERATURE_ENDPOINT,
                    ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
                    ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &counter, false);
            if( status != ESP_ZB_ZCL_STATUS_SUCCESS)
            {
                ESP_LOGE( TAG, "Setting temp attribute failed: %d", status);
            }

            status = esp_zb_zcl_set_attribute_val( HA_ESP_TEMPERATURE_ENDPOINT,
                    ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
                    ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &humidity, false);
            if( status != ESP_ZB_ZCL_STATUS_SUCCESS)
            {
                ESP_LOGE( TAG, "Setting temp attribute failed: %d", status);
            }

            status = esp_zb_zcl_set_attribute_val( HA_ESP_TEMPERATURE_ENDPOINT,
                    ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
                    ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, &rel_pressure, false);
            if( status != ESP_ZB_ZCL_STATUS_SUCCESS)
            {
                ESP_LOGE( TAG, "Setting temp attribute failed: %d", status);
            } 


            counter++;
            if( counter >= temperature_cfg.max_value)
            {
                counter = temperature_cfg.min_value;
            }

            humidity += 10;
            if( humidity >= humidity_cfg.max_value)
            {
                humidity = humidity_cfg.min_value;
            }

            rel_pressure++;
            if( rel_pressure >= pressure_cfg.max_value)
            {
                rel_pressure = pressure_cfg.min_value;
            }
        }
        vTaskDelay( pdMS_TO_TICKS(2000));
    }
}

void app_main(void)
{
    esp_zb_platform_config_t config = {
        .radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(),
        .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(),
    };
    ESP_ERROR_CHECK(nvs_flash_init());
    /* load Zigbee light_bulb platform config to initialization */
    ESP_ERROR_CHECK(esp_zb_platform_config(&config));
    /* hardware related and device init */
    light_driver_init(LIGHT_DEFAULT_OFF);
    xTaskCreate( adc_task, "ADC Task", 4096, NULL, 5, NULL);
    xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL);
}

The changes are:

  1. added another task that will ultimately read the ADCs and other inputs to provide the data to bse sent - right now all it does is send values every 2 seconds for testing purposes
  2. some minor changes to the esp_zb_app_signal_handler to restart on failed connections etc
  3. esp_zb_task now creates the various clusters and devices explicitly rather than some of the ‘higher level’ functions that Espressif provide (for m education as much as anything)
    You wil see that it has a cluster that sets the manufacturer, model etc (change the strings to whatever you want) plus the on-off switch. Other clusters provides the (pseudo) temperature, humidity and pressure values.
    There is a generic ‘analog input’ cluster as well but that is where the ZHA does not provide support and so it is ignored.
    Happy hacking.
    Susan

hello fellow tinkerers - looks like we are fighting the same problems )

@AussieSusan - congrats on getting quirks working !
I took a coward’s way out and reporting values I need as temperature.

a bit behind you in education - maybe someone will find my stuff useful - zigbee-plant-waterer/main at main · eugene-polyakov/zigbee-plant-waterer · GitHub