Thank you all for these tips. I’ve made a lot of progress with the updated configuration which now looks like this on HAOS 17.1:
zha:
zigpy_config:
ota:
extra_providers:
- type: advanced # !!! Please read the message below before enabling OTA updates from raw OTA files !!!
warning: I understand I can *destroy* my devices by enabling OTA updates from
files. Some OTA updates can be mistakenly applied to the wrong
device, breaking it. I am consciously using this at my own risk.
path: /config/ota_peanut
logger:
default: warning
logs:
homeassistant.core: warning
homeassistant.components.zha: debug
bellows.zigbee.application: info
bellows.ezsp: info
zigpy: debug
zigpy_cc: info
zigpy_deconz.zigbee.application: info
zigpy_deconz.api: info
zigpy_xbee.zigbee.application: info
zigpy_xbee.api: info
zigpy_zigate: info
zigpy_znp: info
zhaquirks: info
The OTA filename is /config/ota_peanut/ZPS_CS5490_039.ota
When I write the attribute:
I can see from the logs that it’s able to identify the custom OTA file:
2026-03-13 18:41:07.093 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0005] Decoded ZCL frame: Scenes:WriteAttributesResponseSchema(status_records=[WriteAttributesStatusRecord(status=<Status.SUCCESS: 0>)])
2026-03-13 18:41:07.096 DEBUG (MainThread) [zigpy.event] Emitting event attribute_written with data AttributeWrittenEvent(event_type='attribute_written', device_ieee='00:0d:6f:00:05:49:9d:08', endpoint_id=1, cluster_type=<ClusterType.Server: 0>, cluster_id=5, attribute_name='current_group', attribute_id=2, manufacturer_code=None, value=49502, status=<Status.SUCCESS: 0>) (2 listeners)
2026-03-13 18:41:07.097 DEBUG (MainThread) [homeassistant.components.zha.websocket_api] Set attribute for: cluster_id: [5] cluster_type: [in] endpoint_id: [1] attribute: [2] value: [49502] manufacturer: [UndefinedType._singleton] response: [[[WriteAttributesStatusRecord(status=<Status.SUCCESS: 0>)]]]
2026-03-13 18:41:08.743 DEBUG (MainThread) [zigpy.application] Feeding watchdog
2026-03-13 18:41:08.992 DEBUG (MainThread) [zigpy.application] Received a packet: ZigbeePacket(timestamp=datetime.datetime(2026, 3, 13, 22, 41, 8, 992413, tzinfo=datetime.timezone.utc), priority=None, src=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0F5A), src_ep=1, dst=AddrModeAddress(addr_mode=<AddrMode.NWK: 2>, address=0x0000), dst_ep=1, source_route=None, extended_timeout=False, tsn=142, profile_id=260, cluster_id=25, data=Serialized[b"\x01\r\x01\x00\x02\x10\xc0^'\x00\x00\x00"], tx_options=<TransmitOptions.NONE: 0>, radius=0, non_member_radius=0, lqi=255, rssi=-26)
2026-03-13 18:41:08.993 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Received ZCL frame: '01 0d 01 00 02 10 c0 5e 27 00 00 00'
2026-03-13 18:41:08.993 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x01>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=13, command_id=1, *direction=<Direction.Client_to_Server: 0>)
2026-03-13 18:41:08.993 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Decoded ZCL frame: Ota:QueryNextImageCommand(field_control=<QueryNextImageCommandFieldControl: 0>, manufacturer_code=4098, image_type=24256, current_file_version=39)
2026-03-13 18:41:08.994 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Received command 0x01 (TSN 13): QueryNextImageCommand(field_control=<QueryNextImageCommandFieldControl: 0>, manufacturer_code=4098, image_type=24256, current_file_version=39)
2026-03-13 18:41:08.995 DEBUG (MainThread) [zigpy.event] Emitting event attribute_updated with data AttributeUpdatedEvent(event_type='attribute_updated', device_ieee='00:0d:6f:00:05:49:9d:08', endpoint_id=1, cluster_type=<ClusterType.Client: 1>, cluster_id=25, attribute_name='current_file_version', attribute_id=2, manufacturer_code=None, value=39) (2 listeners)
2026-03-13 18:41:08.996 WARNING (MainThread) [zha] Received unknown event: DeviceFirmwareInfoUpdatedEvent(event_type='zha_device_updated_event', event='zha_device_updated_event', old_firmware_version='0x00000000', new_firmware_version='0x00000027')
2026-03-13 18:41:08.998 DEBUG (MainThread) [homeassistant.components.zha.entity] update.securifi_ltd_unk_model_firmware: Handling event from entity: EntityStateChangedEvent(event_type='entity', event='state_changed', platform=<Platform.UPDATE: 'update'>, unique_id='00:0d:6f:00:05:49:9d:08-1-25-firmware_update', device_ieee=00:0d:6f:00:05:49:9d:08, endpoint_id=1, group_id=None)
2026-03-13 18:41:08.999 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Sending reply header: ZCLHeader(frame_control=FrameControl<0x19>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False), tsn=13, command_id=2, *direction=<Direction.Server_to_Client: 1>)
2026-03-13 18:41:08.999 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Sending reply: query_next_image_response(status=<Status.NO_IMAGE_AVAILABLE: 152>, manufacturer_code=None, image_type=None, file_version=None, image_size=None)
2026-03-13 18:41:09.445 DEBUG (MainThread) [zigpy.ota] Loaded 20 images from provider: ZigpyOtaProvider(url='https://raw.githubusercontent.com/zigpy/zigpy-ota/release/version/stable.json', channel='stable', manufacturer_ids=())
2026-03-13 18:41:09.457 DEBUG (MainThread) [zigpy.ota] Loaded 1 images from provider: AdvancedFileProvider(path=PosixPath('/config/ota_peanut'), manufacturer_ids=())
2026-03-13 18:41:09.462 DEBUG (MainThread) [zigpy.ota] Caching image OtaImageWithMetadata(metadata=LocalOtaImageMetadata(file_version=57, manufacturer_id=4098, image_type=24256, checksum='sha1:65f29a4c2cee6601e34ad08a980c33076c5316b7', file_size=155646, manufacturer_names=(), model_names=(), changelog=None, release_notes=None, release_url=None, min_hardware_version=None, max_hardware_version=None, min_current_file_version=None, max_current_file_version=None, specificity=None, source='Advanced file provider (/config/ota_peanut)', path=PosixPath('/config/ota_peanut/ZPS_CS5490_039.ota')), firmware=OTAImage(header=OTAImageHeader(upgrade_file_id=200208670, header_version=256, header_length=56, field_control=<FieldControl: 0>, manufacturer_id=4098, image_type=24256, file_version=57, stack_version=2, header_string=<'peanut Power Plug'>, image_size=155646, *device_specific_file=False, *hardware_versions_present=False, *security_credential_version_present=False), subelements=[<SubElement(tag_id=<ElementTagId.UPGRADE_IMAGE: 0>, data=[155584:0000008c0201e350080020006ade5513e81c0020514e0208e5...ffffffffffffff])>]))
2026-03-13 18:41:09.464 DEBUG (MainThread) [homeassistant.components.zha.entity] update.securifi_ltd_unk_model_firmware: Handling event from entity: EntityStateChangedEvent(event_type='entity', event='state_changed', platform=<Platform.UPDATE: 'update'>, unique_id='00:0d:6f:00:05:49:9d:08-1-25-firmware_update', device_ieee=00:0d:6f:00:05:49:9d:08, endpoint_id=1, group_id=None)
Specifically DeviceFirmwareInfoUpdatedEvent(event_type='zha_device_updated_event', event='zha_device_updated_event', old_firmware_version='0x00000000', new_firmware_version='0x00000027')
and
Loaded 1 images from provider: AdvancedFileProvider(path=PosixPath('/config/ota_peanut'), manufacturer_ids=())
But then I notice its saying that the there is no image file to be sent!
Sending reply: query_next_image_response(status=<Status.NO_IMAGE_AVAILABLE: 152>, manufacturer_code=None, image_type=None, file_version=None, image_size=None)
It seems that it’s not able to match the firmware file with the peanut plug.
And I keep seeing this repeated over and over again.
2026-03-13 18:50:54.897 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x01>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 0>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=15, command_id=1, *direction=<Direction.Client_to_Server: 0>)
2026-03-13 18:50:54.898 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Decoded ZCL frame: Ota:QueryNextImageCommand(field_control=<QueryNextImageCommandFieldControl: 0>, manufacturer_code=4098, image_type=24256, current_file_version=39)
2026-03-13 18:50:54.898 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Received command 0x01 (TSN 15): QueryNextImageCommand(field_control=<QueryNextImageCommandFieldControl: 0>, manufacturer_code=4098, image_type=24256, current_file_version=39)
2026-03-13 18:50:54.898 DEBUG (MainThread) [zigpy.event] Emitting event attribute_updated with data AttributeUpdatedEvent(event_type='attribute_updated', device_ieee='00:0d:6f:00:05:49:9d:08', endpoint_id=1, cluster_type=<ClusterType.Client: 1>, cluster_id=25, attribute_name='current_file_version', attribute_id=2, manufacturer_code=None, value=39) (2 listeners)
2026-03-13 18:50:54.901 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Sending reply header: ZCLHeader(frame_control=FrameControl<0x19>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False), tsn=15, command_id=2, *direction=<Direction.Server_to_Client: 1>)
2026-03-13 18:50:54.901 DEBUG (MainThread) [zigpy.zcl] [0x0F5A:1:0x0019] Sending reply: query_next_image_response(status=<Status.NO_IMAGE_AVAILABLE: 152>, manufacturer_code=None, image_type=None, file_version=None, image_size=None)
2026-03-13 18:50:55.012 DEBUG (MainThread) [zigpy.ota] Provider ZigpyOtaProvider(url='https://raw.githubusercontent.com/zigpy/zigpy-ota/release/version/stable.json', channel='stable', manufacturer_ids=()) was recently contacted, using cached response
2026-03-13 18:50:55.013 DEBUG (MainThread) [zigpy.ota] Provider AdvancedFileProvider(path=PosixPath('/config/ota_peanut'), manufacturer_ids=()) was recently contacted, using cached response
I’m a little confused here. What is supposed to happen? How do I know if it’s sending the firmware image to the file and when it’s completed? Is there another way to force sending the image file to the plug? I’ve tried to pair it multiple times but nothing. Sometimes I see the solid red light when it tries to update the firmware.
Any ideas?