Skip to content

Commit

Permalink
Complete implementation of ZCLPowerSupply.
Browse files Browse the repository at this point in the history
  • Loading branch information
pwood committed Jun 4, 2024
1 parent 38d740c commit 6a1fdd8
Show file tree
Hide file tree
Showing 19 changed files with 1,089 additions and 113 deletions.
5 changes: 3 additions & 2 deletions attribute/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ func (z *zclMonitor) zclFilter(a zigbee.IEEEAddress, _ zigbee.ApplicationMessage
return a == z.ieeeAddress &&
m.SourceEndpoint == z.remoteEndpoint &&
m.DestinationEndpoint == z.localEndpoint &&
m.Direction == zcl.ServerToClient
m.Direction == zcl.ServerToClient &&
m.ClusterID == z.clusterID
}

func (z *zclMonitor) zclMessage(m communicator.MessageWithSource) {
Expand All @@ -265,7 +266,7 @@ func (z *zclMonitor) zclMessage(m communicator.MessageWithSource) {
}
case *global.ReadAttributesResponse:
for _, record := range cmd.Records {
if record.Identifier == z.attributeID && record.DataTypeValue.DataType == z.attributeDataType && record.Status == 0 {
if record.Status == 0 && record.Identifier == z.attributeID && record.DataTypeValue.DataType == z.attributeDataType {
z.callback(record.Identifier, *record.DataTypeValue)
}
}
Expand Down
27 changes: 27 additions & 0 deletions attribute/monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,13 @@ func Test_zclMonitor_zclFilter(t *testing.T) {
z.ieeeAddress = zigbee.GenerateLocalAdministeredIEEEAddress()
z.localEndpoint = 1
z.remoteEndpoint = 2
z.clusterID = 3

match := z.zclFilter(z.ieeeAddress, zigbee.ApplicationMessage{}, zcl.Message{
SourceEndpoint: z.remoteEndpoint,
DestinationEndpoint: z.localEndpoint,
Direction: zcl.ServerToClient,
ClusterID: 3,
})

assert.True(t, match)
Expand All @@ -467,11 +469,13 @@ func Test_zclMonitor_zclFilter(t *testing.T) {
z.ieeeAddress = zigbee.GenerateLocalAdministeredIEEEAddress()
z.localEndpoint = 1
z.remoteEndpoint = 2
z.clusterID = 3

match := z.zclFilter(zigbee.GenerateLocalAdministeredIEEEAddress(), zigbee.ApplicationMessage{}, zcl.Message{
SourceEndpoint: z.remoteEndpoint,
DestinationEndpoint: z.localEndpoint,
Direction: zcl.ServerToClient,
ClusterID: 3,
})

assert.False(t, match)
Expand All @@ -482,11 +486,13 @@ func Test_zclMonitor_zclFilter(t *testing.T) {
z.ieeeAddress = zigbee.GenerateLocalAdministeredIEEEAddress()
z.localEndpoint = 1
z.remoteEndpoint = 2
z.clusterID = 3

match := z.zclFilter(z.ieeeAddress, zigbee.ApplicationMessage{}, zcl.Message{
SourceEndpoint: 99,
DestinationEndpoint: z.localEndpoint,
Direction: zcl.ServerToClient,
ClusterID: 3,
})

assert.False(t, match)
Expand All @@ -497,11 +503,13 @@ func Test_zclMonitor_zclFilter(t *testing.T) {
z.ieeeAddress = zigbee.GenerateLocalAdministeredIEEEAddress()
z.localEndpoint = 1
z.remoteEndpoint = 2
z.clusterID = 3

match := z.zclFilter(z.ieeeAddress, zigbee.ApplicationMessage{}, zcl.Message{
SourceEndpoint: z.remoteEndpoint,
DestinationEndpoint: 99,
Direction: zcl.ServerToClient,
ClusterID: 3,
})

assert.False(t, match)
Expand All @@ -512,11 +520,30 @@ func Test_zclMonitor_zclFilter(t *testing.T) {
z.ieeeAddress = zigbee.GenerateLocalAdministeredIEEEAddress()
z.localEndpoint = 1
z.remoteEndpoint = 2
z.clusterID = 3

match := z.zclFilter(z.ieeeAddress, zigbee.ApplicationMessage{}, zcl.Message{
SourceEndpoint: z.remoteEndpoint,
DestinationEndpoint: z.localEndpoint,
Direction: zcl.ClientToServer,
ClusterID: 3,
})

assert.False(t, match)
})

t.Run("returns false if cluster doesn't match", func(t *testing.T) {
z := zclMonitor{}
z.ieeeAddress = zigbee.GenerateLocalAdministeredIEEEAddress()
z.localEndpoint = 1
z.remoteEndpoint = 2
z.clusterID = 1

match := z.zclFilter(z.ieeeAddress, zigbee.ApplicationMessage{}, zcl.Message{
SourceEndpoint: z.remoteEndpoint,
DestinationEndpoint: z.localEndpoint,
Direction: zcl.ServerToClient,
ClusterID: 3,
})

assert.False(t, match)
Expand Down
7 changes: 7 additions & 0 deletions enumerate_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/shimmeringbee/zda/implcaps/factory"
"github.com/shimmeringbee/zda/rules"
"github.com/shimmeringbee/zigbee"
"runtime/debug"
"slices"
"sort"
"sync"
Expand Down Expand Up @@ -61,6 +62,7 @@ func (e enumerateDevice) startEnumeration(ctx context.Context, n *node) error {
}

go e.enumerate(ctx, n)

return nil
}

Expand Down Expand Up @@ -419,6 +421,11 @@ func (e enumerateDevice) enumerateCapabilityOnDevice(ctx context.Context, d *dev
}

e.logger.LogInfo(ctx, "Attaching capability implementation.")
defer func() {
if r := recover(); r != nil {
e.logger.LogPanic(ctx, "Capability paniced during enumeration!", logwrap.Datum("Panic", r), logwrap.Datum("Trace", string(debug.Stack())))
}
}()
attached, err := c.Enumerate(ctx, settings)
if err != nil {
e.logger.LogWarn(ctx, "Errored while attaching new capability.", logwrap.Err(err), logwrap.Datum("Attached", attached))
Expand Down
5 changes: 5 additions & 0 deletions implcaps/factory/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/shimmeringbee/zda/implcaps/generic"
"github.com/shimmeringbee/zda/implcaps/zcl/humidity_sensor"
"github.com/shimmeringbee/zda/implcaps/zcl/identify"
"github.com/shimmeringbee/zda/implcaps/zcl/power_supply"
"github.com/shimmeringbee/zda/implcaps/zcl/pressure_sensor"
"github.com/shimmeringbee/zda/implcaps/zcl/temperature_sensor"
)
Expand All @@ -16,13 +17,15 @@ const ZCLTemperatureSensor = "ZCLTemperatureSensor"
const ZCLHumiditySensor = "ZCLHumiditySensor"
const ZCLPressureSensor = "ZCLPressureSensor"
const ZCLIdentify = "ZCLIdentify"
const ZCLPowerSupply = "ZCLPowerSupply"

var Mapping = map[string]da.Capability{
GenericProductInformation: capabilities.ProductInformationFlag,
ZCLTemperatureSensor: capabilities.TemperatureSensorFlag,
ZCLHumiditySensor: capabilities.RelativeHumiditySensorFlag,
ZCLPressureSensor: capabilities.PressureSensorFlag,
ZCLIdentify: capabilities.IdentifyFlag,
ZCLPowerSupply: capabilities.PowerSupplyFlag,
}

func Create(name string, iface implcaps.ZDAInterface) implcaps.ZDACapability {
Expand All @@ -37,6 +40,8 @@ func Create(name string, iface implcaps.ZDAInterface) implcaps.ZDACapability {
return pressure_sensor.NewPressureSensor(iface)
case ZCLIdentify:
return identify.NewIdentify(iface)
case ZCLPowerSupply:
return power_suply.NewPowerSupply(iface)
default:
return nil
}
Expand Down
3 changes: 3 additions & 0 deletions implcaps/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package implcaps
import (
"context"
"github.com/shimmeringbee/da"
"github.com/shimmeringbee/logwrap"
"github.com/shimmeringbee/persistence"
"github.com/shimmeringbee/zcl"
"github.com/shimmeringbee/zcl/communicator"
Expand Down Expand Up @@ -60,4 +61,6 @@ type ZDAInterface interface {
ZCLRegister(func(*zcl.CommandRegistry))
//TransmissionLookup resolves destination information for a capability.
TransmissionLookup(da.Device, zigbee.ProfileID) (zigbee.IEEEAddress, zigbee.Endpoint, bool, uint8)
//Logger returns a logger to be used.
Logger() logwrap.Logger
}
5 changes: 5 additions & 0 deletions implcaps/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package implcaps

import (
"github.com/shimmeringbee/da"
"github.com/shimmeringbee/logwrap"
"github.com/shimmeringbee/zcl"
"github.com/shimmeringbee/zcl/communicator"
"github.com/shimmeringbee/zda/attribute"
Expand All @@ -13,6 +14,10 @@ type MockZDAInterface struct {
mock.Mock
}

func (m *MockZDAInterface) Logger() logwrap.Logger {
return m.Called().Get(0).(logwrap.Logger)
}

func (m *MockZDAInterface) ZCLRegister(f func(*zcl.CommandRegistry)) {
m.Called(f)
}
Expand Down
4 changes: 1 addition & 3 deletions implcaps/zcl/humidity_sensor/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ func (i *Implementation) Load(ctx context.Context) (bool, error) {

func (i *Implementation) Enumerate(ctx context.Context, m map[string]any) (bool, error) {
endpoint := implcaps.Get(m, "ZigbeeEndpoint", zigbee.Endpoint(1))
clusterId := implcaps.Get(m, "ZigbeeHumidityMeasurementClusterID", zcl.RelativeHumidityMeasurementId)
attributeId := implcaps.Get(m, "ZigbeeHumidityMeasurementAttributeID", relative_humidity_measurement.MeasuredValue)

reporting := attribute.ReportingConfig{
Mode: attribute.AttemptConfigureReporting,
Expand All @@ -72,7 +70,7 @@ func (i *Implementation) Enumerate(ctx context.Context, m map[string]any) (bool,
Interval: 1 * time.Minute,
}

if err := i.am.Attach(ctx, endpoint, clusterId, attributeId, zcl.TypeUnsignedInt16, reporting, polling); err != nil {
if err := i.am.Attach(ctx, endpoint, zcl.RelativeHumidityMeasurementId, relative_humidity_measurement.MeasuredValue, zcl.TypeUnsignedInt16, reporting, polling); err != nil {
return false, err
}

Expand Down
22 changes: 1 addition & 21 deletions implcaps/zcl/humidity_sensor/impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestImplementation_Load(t *testing.T) {
}

func TestImplementation_Enumerate(t *testing.T) {
t.Run("attaches to the attribute monitor, using default attributes", func(t *testing.T) {
t.Run("attaches to the attribute monitor", func(t *testing.T) {
mm := &attribute.MockMonitor{}
defer mm.AssertExpectations(t)

Expand All @@ -96,26 +96,6 @@ func TestImplementation_Enumerate(t *testing.T) {
assert.NoError(t, err)
})

t.Run("attaches to the attribute monitor, using overridden attributes", func(t *testing.T) {
mm := &attribute.MockMonitor{}
defer mm.AssertExpectations(t)

mm.On("Attach", mock.Anything, zigbee.Endpoint(0x02), zigbee.ClusterID(0x500), zcl.AttributeID(0x10), zcl.TypeUnsignedInt16, mock.Anything, mock.Anything).Return(nil)

i := NewHumiditySensor(nil)
i.am = mm

attributes := map[string]any{
"ZigbeeEndpoint": zigbee.Endpoint(0x02),
"ZigbeeHumidityMeasurementClusterID": zigbee.ClusterID(0x500),
"ZigbeeHumidityMeasurementAttributeID": zcl.AttributeID(0x10),
}
attached, err := i.Enumerate(context.TODO(), attributes)

assert.True(t, attached)
assert.NoError(t, err)
})

t.Run("fails if attach to the attribute monitor fails", func(t *testing.T) {
mm := &attribute.MockMonitor{}
defer mm.AssertExpectations(t)
Expand Down
15 changes: 2 additions & 13 deletions implcaps/zcl/identify/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ type Implementation struct {
am attribute.Monitor
zi implcaps.ZDAInterface

clusterId zigbee.ClusterID
remoteEndpoint zigbee.Endpoint

timerMutex *sync.Mutex
Expand Down Expand Up @@ -66,13 +65,6 @@ func (i *Implementation) Load(ctx context.Context) (bool, error) {
return false, fmt.Errorf("monitor missing config parameter: %s", implcaps.RemoteEndpointKey)
}

if v, ok := i.s.Int(implcaps.ClusterIdKey); ok {
i.clusterId = zigbee.ClusterID(v)
} else {
// i.logger.Error(ctx, "Required config parameter missing.", logwrap.Datum("name", implcaps.ClusterIdKey))
return false, fmt.Errorf("monitor missing config parameter: %s", implcaps.ClusterIdKey)
}

if err := i.am.Load(ctx); err != nil {
return false, err
} else {
Expand All @@ -82,10 +74,7 @@ func (i *Implementation) Load(ctx context.Context) (bool, error) {

func (i *Implementation) Enumerate(ctx context.Context, m map[string]any) (bool, error) {
i.remoteEndpoint = implcaps.Get(m, "ZigbeeEndpoint", zigbee.Endpoint(1))
i.clusterId = implcaps.Get(m, "ZigbeeIdentifyClusterID", zcl.IdentifyId)
attributeId := implcaps.Get(m, "ZigbeeIdentifyDurationAttributeID", identify.IdentifyTime)

i.s.Set(implcaps.ClusterIdKey, int(i.clusterId))
i.s.Set(implcaps.RemoteEndpointKey, int(i.remoteEndpoint))

reporting := attribute.ReportingConfig{
Expand All @@ -100,7 +89,7 @@ func (i *Implementation) Enumerate(ctx context.Context, m map[string]any) (bool,
Interval: 1 * time.Minute,
}

if err := i.am.Attach(ctx, i.remoteEndpoint, i.clusterId, attributeId, zcl.TypeUnsignedInt16, reporting, polling); err != nil {
if err := i.am.Attach(ctx, i.remoteEndpoint, zcl.IdentifyId, identify.IdentifyTime, zcl.TypeUnsignedInt16, reporting, polling); err != nil {
return false, err
}

Expand Down Expand Up @@ -213,7 +202,7 @@ func (i *Implementation) Identify(ctx context.Context, duration time.Duration) e
Direction: zcl.ClientToServer,
TransactionSequence: seq,
Manufacturer: zigbee.NoManufacturer,
ClusterID: i.clusterId,
ClusterID: zcl.IdentifyId,
SourceEndpoint: localEndpoint,
DestinationEndpoint: i.remoteEndpoint,
CommandIdentifier: identify.IdentifyId,
Expand Down
26 changes: 2 additions & 24 deletions implcaps/zcl/identify/impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestImplementation_Load(t *testing.T) {
}

func TestImplementation_Enumerate(t *testing.T) {
t.Run("attaches to the attribute monitor, using default attributes", func(t *testing.T) {
t.Run("attaches to the attribute monitor", func(t *testing.T) {
mm := &attribute.MockMonitor{}
defer mm.AssertExpectations(t)

Expand All @@ -104,27 +104,6 @@ func TestImplementation_Enumerate(t *testing.T) {
assert.NoError(t, err)
})

t.Run("attaches to the attribute monitor, using overridden attributes", func(t *testing.T) {
mm := &attribute.MockMonitor{}
defer mm.AssertExpectations(t)

mm.On("Attach", mock.Anything, zigbee.Endpoint(0x02), zigbee.ClusterID(0x500), zcl.AttributeID(0x10), zcl.TypeUnsignedInt16, mock.Anything, mock.Anything).Return(nil)

i := &Implementation{}
i.am = mm
i.s = memory.New()

attributes := map[string]any{
"ZigbeeEndpoint": zigbee.Endpoint(0x02),
"ZigbeeIdentifyClusterID": zigbee.ClusterID(0x500),
"ZigbeeIdentifyDurationAttributeID": zcl.AttributeID(0x10),
}
attached, err := i.Enumerate(context.TODO(), attributes)

assert.True(t, attached)
assert.NoError(t, err)
})

t.Run("fails if attach to the attribute monitor fails", func(t *testing.T) {
mm := &attribute.MockMonitor{}
defer mm.AssertExpectations(t)
Expand Down Expand Up @@ -282,15 +261,14 @@ func TestImplementation_Identify(t *testing.T) {

mzi.On("TransmissionLookup", md, zigbee.ProfileHomeAutomation).Return(ieee, localEndpoint, false, seq)

i.clusterId = zcl.IdentifyId
i.remoteEndpoint = 4

expectedMsg := zcl.Message{
FrameType: zcl.FrameLocal,
Direction: zcl.ClientToServer,
TransactionSequence: uint8(seq),
Manufacturer: zigbee.NoManufacturer,
ClusterID: i.clusterId,
ClusterID: zcl.IdentifyId,
SourceEndpoint: localEndpoint,
DestinationEndpoint: i.remoteEndpoint,
CommandIdentifier: identify.IdentifyId,
Expand Down
Loading

0 comments on commit 6a1fdd8

Please sign in to comment.