diff --git a/meter/homematic/connection.go b/meter/homematic/connection.go index 31775e2550..30f0f854d2 100644 --- a/meter/homematic/connection.go +++ b/meter/homematic/connection.go @@ -84,10 +84,6 @@ func (c *Connection) XmlCmd(method, channel string, values ...Param) (MethodResp return hmr, err } - if strings.Contains(string(res), "faultCode") { - return hmr, fmt.Errorf("ccu: %s", string(res)) - } - // correct Homematic IP Legacy API (CCU port 2010) method response encoding value res = []byte(strings.Replace(string(res), "ISO-8859-1", "UTF-8", 1)) @@ -98,7 +94,7 @@ func (c *Connection) XmlCmd(method, channel string, values ...Param) (MethodResp return hmr, err } - return hmr, err + return hmr, parseError(hmr) } // Initialze CCU methods via system.listMethods call @@ -149,3 +145,26 @@ func (c *Connection) GridTotalEnergy() (float64, error) { res, err := c.XmlCmd("getValue", c.MeterChannel, Param{CCUString: "IEC_ENERGY_COUNTER"}) return res.Value.CCUFloat, err } + +// parseError checks on Homematic CCU error codes +// Refer to page 30 of https://homematic-ip.com/sites/default/files/downloads/HM_XmlRpc_API.pdf +func parseError(res MethodResponse) error { + var faultCode int64 + var faultString string + + faultCode = 0 + for _, f := range res.Fault { + if f.Name == "faultCode" { + faultCode = f.Value.CCUInt + } + if f.Name == "faultString" { + faultString = f.Value.CCUString + } + } + + if faultCode != 0 { + return fmt.Errorf("%s (%v)", faultString, faultCode) + } + + return nil +} diff --git a/meter/homematic/types.go b/meter/homematic/types.go index f9ed85b508..ee0d84caba 100644 --- a/meter/homematic/types.go +++ b/meter/homematic/types.go @@ -21,7 +21,19 @@ type MethodCall struct { Params []Param `xml:"params>param,omitempty"` } +type Member struct { + Name string `xml:"name,omitempty"` + Value FaultValue `xml:"value,omitempty"` +} + +type FaultValue struct { + XMLName xml.Name `xml:"value"` + CCUString string `xml:",chardata"` + CCUInt int64 `xml:"i4,omitempty"` +} + type MethodResponse struct { XMLName xml.Name `xml:"methodResponse"` Value Param `xml:"params>param,omitempty"` + Fault []Member `xml:"fault>value>struct>member,omitempty"` } diff --git a/meter/homematic/types_test.go b/meter/homematic/types_test.go new file mode 100644 index 0000000000..9d99924819 --- /dev/null +++ b/meter/homematic/types_test.go @@ -0,0 +1,37 @@ +package homematic + +import ( + "encoding/xml" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +// Test MethodResponse response +func TestUnmarshalMethodResponse(t *testing.T) { + + { + // Double response test + var res MethodResponse + + xmlstr := `20698.0` + assert.NoError(t, xml.Unmarshal([]byte(strings.Replace(string(xmlstr), "ISO-8859-1", "UTF-8", 1)), &res)) + + assert.Equal(t, float64(20698), res.Value.CCUFloat) + } + + { + // Faulty response test + var res MethodResponse + + xmlstr := `faultCode-2faultStringInvalid device` + assert.NoError(t, xml.Unmarshal([]byte(strings.Replace(string(xmlstr), "ISO-8859-1", "UTF-8", 1)), &res)) + + assert.Equal(t, "faultCode", res.Fault[0].Name) + assert.Equal(t, int64(-2), res.Fault[0].Value.CCUInt) + assert.Equal(t, "faultString", res.Fault[1].Name) + assert.Equal(t, "Invalid device", res.Fault[1].Value.CCUString) + } + +}