mirror of
https://github.com/nikdoof/hapz2m.git
synced 2026-01-30 10:28:21 +00:00
Only process EndDevices during add and more verbose errors
If a Coordinator is present in the device list, AddDevicesFromJSON will fail catastrophically, which shouldn't happen. Therefore, make sure only EndDevices are considered during add. Also updated the tests to check for this. Added a device descriptor for failed adds. This will help with identifying which device failed (and perhaps, why).
This commit is contained in:
11
bridge.go
11
bridge.go
@@ -442,6 +442,12 @@ func (br *Bridge) accessories() []*accessory.A {
|
|||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deviceJsonDescriptor(d Device) []byte {
|
||||||
|
d.Definition = nil
|
||||||
|
j, _ := json.Marshal(d)
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
// Creates and calls AddDevice() based on the JSON definitions from zigbee2mqtt/bridge/devices.
|
// Creates and calls AddDevice() based on the JSON definitions from zigbee2mqtt/bridge/devices.
|
||||||
func (br *Bridge) AddDevicesFromJSON(devJson []byte) error {
|
func (br *Bridge) AddDevicesFromJSON(devJson []byte) error {
|
||||||
var devices []Device
|
var devices []Device
|
||||||
@@ -458,12 +464,13 @@ func (br *Bridge) AddDevicesFromJSON(devJson []byte) error {
|
|||||||
if err == ErrDeviceSkipped || err == ErrUnknownDeviceType {
|
if err == ErrDeviceSkipped || err == ErrUnknownDeviceType {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return err
|
return fmt.Errorf("createAccessory failed: %+v %s", err, deviceJsonDescriptor(dev))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = br.AddDevice(&dev, acc, exp)
|
err = br.AddDevice(&dev, acc, exp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("AddDevice failed: %+v %s", err, deviceJsonDescriptor(dev))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const ContactSensorTemplate = `
|
|||||||
"interviewing": false,
|
"interviewing": false,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"supported": true,
|
"supported": true,
|
||||||
|
"type": "EndDevice",
|
||||||
"definition": {
|
"definition": {
|
||||||
"exposes": [
|
"exposes": [
|
||||||
{
|
{
|
||||||
@@ -41,28 +42,24 @@ func fileSize(path string) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBridgePersistState(t *testing.T) {
|
func TestBridgePersistState(t *testing.T) {
|
||||||
dir, err := os.MkdirTemp("", "hapz2m-bridge*")
|
dir := t.TempDir()
|
||||||
if err != nil {
|
b := NewBridge(context.Background(), dir)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
|
|
||||||
var m sync.Map
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
b := NewBridge(ctx, dir)
|
|
||||||
|
|
||||||
// devices
|
// devices
|
||||||
s1 := fmt.Appendf(nil, ContactSensorTemplate, 10)
|
s1 := fmt.Appendf(nil, ContactSensorTemplate, 10)
|
||||||
s2 := fmt.Appendf(nil, ContactSensorTemplate, 20)
|
s2 := fmt.Appendf(nil, ContactSensorTemplate, 20)
|
||||||
|
|
||||||
err = b.AddDevicesFromJSON(fmt.Appendf(nil, "[%s, %s]", s1, s2))
|
err := b.AddDevicesFromJSON(fmt.Appendf(nil, "[%s, %s]", s1, s2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot add devices: %v", err)
|
t.Fatalf("cannot add devices: %v", err)
|
||||||
}
|
}
|
||||||
|
if len(b.devices) != 2 {
|
||||||
|
t.Fatalf("devices not added to bridge!")
|
||||||
|
}
|
||||||
|
|
||||||
// empty state, should have no errors
|
// empty state, should have no errors
|
||||||
t.Logf("loading from empty db")
|
t.Logf("loading from empty db")
|
||||||
|
var m sync.Map
|
||||||
if err := b.loadZ2MState(&m); err != nil {
|
if err := b.loadZ2MState(&m); err != nil {
|
||||||
t.Errorf("empty state load should not error: %v", err)
|
t.Errorf("empty state load should not error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -95,7 +92,7 @@ func TestBridgePersistState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// re-create with less devices
|
// re-create with less devices
|
||||||
b2 := NewBridge(ctx, dir)
|
b2 := NewBridge(context.Background(), t.TempDir())
|
||||||
b2.AddDevicesFromJSON(fmt.Appendf(nil, "[%s]", s1))
|
b2.AddDevicesFromJSON(fmt.Appendf(nil, "[%s]", s1))
|
||||||
|
|
||||||
t.Logf("loading from initial db")
|
t.Logf("loading from initial db")
|
||||||
@@ -115,3 +112,25 @@ func TestBridgePersistState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBridgeAddCoordinator(t *testing.T) {
|
||||||
|
b := NewBridge(context.Background(), t.TempDir())
|
||||||
|
|
||||||
|
err := b.AddDevicesFromJSON([]byte(`
|
||||||
|
[{
|
||||||
|
"definition": null,
|
||||||
|
"disabled": false,
|
||||||
|
"endpoints": [{"foo": true}],
|
||||||
|
"friendly_name": "Coordinator",
|
||||||
|
"ieee_address": "0x0022222200000000",
|
||||||
|
"interview_completed": true,
|
||||||
|
"interviewing": false,
|
||||||
|
"network_address": 0,
|
||||||
|
"supported": true,
|
||||||
|
"type": "Coordinator"
|
||||||
|
}]
|
||||||
|
`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot add coordinator: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
15
z2m.go
15
z2m.go
@@ -76,7 +76,8 @@ func initExposeMappings(exposes ...*ExposeMapping) error {
|
|||||||
func createAccessory(dev *Device) (*accessory.A, []*ExposeMapping, error) {
|
func createAccessory(dev *Device) (*accessory.A, []*ExposeMapping, error) {
|
||||||
if dev.Disabled ||
|
if dev.Disabled ||
|
||||||
!dev.Supported ||
|
!dev.Supported ||
|
||||||
!dev.InterviewCompleted {
|
!dev.InterviewCompleted ||
|
||||||
|
dev.Type != "EndDevice" {
|
||||||
return nil, nil, ErrDeviceSkipped
|
return nil, nil, ErrDeviceSkipped
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,14 +279,14 @@ type Device struct {
|
|||||||
IEEEAddress string `json:"ieee_address"`
|
IEEEAddress string `json:"ieee_address"`
|
||||||
InterviewCompleted bool `json:"interview_completed"`
|
InterviewCompleted bool `json:"interview_completed"`
|
||||||
Interviewing bool `json:"interviewing"`
|
Interviewing bool `json:"interviewing"`
|
||||||
Manufacturer string `json:"manufacturer"`
|
Manufacturer string `json:"manufacturer,omitempty"`
|
||||||
ModelId string `json:"model_id"`
|
ModelId string `json:"model_id,omitempty"`
|
||||||
NetworkAddress int `json:"network_address"`
|
NetworkAddress int `json:"network_address"`
|
||||||
PowerSource string `json:"power_source"`
|
PowerSource string `json:"power_source,omitempty"`
|
||||||
SoftwareBuildId string `json:"software_build_id"`
|
SoftwareBuildId string `json:"software_build_id,omitempty"`
|
||||||
DateCode string `json:"date_code"`
|
DateCode string `json:"date_code,omitempty"`
|
||||||
|
|
||||||
Definition *DevDefinition `json:"definition"`
|
Definition *DevDefinition `json:"definition,omitempty"`
|
||||||
|
|
||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
Supported bool `json:"supported"`
|
Supported bool `json:"supported"`
|
||||||
|
|||||||
Reference in New Issue
Block a user