diff --git a/include/arke.h b/include/arke.h index b327cbf..4aa7a99 100644 --- a/include/arke.h +++ b/include/arke.h @@ -1,161 +1,161 @@ #pragma once #include "inttypes.h" #ifdef __cplusplus extern "C"{ #endif //__cplusplus typedef enum ArkeMessageType_e { ARKE_NETWORK_CONTROL_COMMAND = 0x00, ARKE_HIGH_PRIORITY_MESSAGE = 0x01, ARKE_MESSAGE = 0x02, ARKE_HEARTBEAT = 0x03, ARKE_MESSAGE_TYPE_MASK = 0x03 << 9 } ArkeMessageType; typedef enum ArkeNodeClass_e { ARKE_BROADCAST = 0x0, ARKE_ZEUS = 0x38, ARKE_HELIOS = 0x34, ARKE_CELAENO = 0x30, ARKE_NODE_CLASS_MASK = 0x3f << 3 } ArkeNodeClass; typedef enum ArkeNetworkCommand_e { ARKE_RESET_REQUEST = 0x00, ARKE_SYNCHRONISATION = 0x01, ARKE_HEARTBEAT_REQUEST = 0x07, ARKE_SUBID_MASK = 0x07 } ArkeNetworkCommand; //#define ARKE_SUBID_MASK ARKE_HEARTBEAT_REQUEST typedef enum ArkeMessageClass_e { ARKE_ZEUS_SET_POINT = 0x38, ARKE_ZEUS_REPORT = 0x39, ARKE_ZEUS_VIBRATION_REPORT = 0x3a, ARKE_ZEUS_CONFIG = 0x3b, ARKE_ZEUS_STATUS = 0x3c, ARKE_ZEUS_CONTROL_POINT = 0x3d, ARKE_HELIOS_SET_POINT = 0x34, ARKE_HELIOS_PULSE_MODE = 0x35, ARKE_CELAENO_SET_POINT = 0x30, ARKE_CELAENO_STATUS = 0x31, ARKE_CELAENO_CONFIG = 0x32 } ArkeMessageClass; struct ArkeZeusSetPoint_t { uint16_t Humidity; uint16_t Temperature; uint8_t Wind; } __attribute__((packed)); typedef struct ArkeZeusSetPoint_t ArkeZeusSetPoint; struct ArkeZeusReport_t { uint16_t Humidity:14; uint16_t Temperature1:14; uint16_t Temperature2:12; uint16_t Temperature3:12; uint16_t Temperature4:12; } __attribute__((packed)); typedef struct ArkeZeusReport_t ArkeZeusReport; struct ArkePIDConfig_t { uint8_t ProportionalMult; uint8_t DerivativeMult; uint8_t IntegralMult; uint8_t DividerPower:4; uint8_t DividerPowerInt:4; } __attribute__((packed)); typedef struct ArkePIDConfig_t ArkePIDConfig; struct ArkeZeusConfig_t { ArkePIDConfig Humidity; ArkePIDConfig Temperature; } __attribute__((packed)); typedef struct ArkeZeusConfig_t ArkeZeusConfig; #define ARKE_FAN_AGING_ALERT (0x4000) #define ARKE_FAN_STALL_ALERT (0x8000) #define ARKE_FAN_RPM_MASK (0x3fff) #define ArkeFanAging(status) (((status).fanStatus & ARKE_FAN_AGING_ALERT) != 0x0000) #define ArkeFanStall(status) (((status).fanStatus & ARKE_FAN_STALL_ALERT) != 0x0000) #define ArkeFanRPM(status) ( (status).fanStatus & ARKE_FAN_RPM_MASK ) typedef uint16_t ArkeFanStatus; typedef enum ArkeZeusStatus_e { - ARKE_ZEUS_IDLE = 0, - ARKE_ZEUS_ACTIVE = (1 << 0), + ARKE_ZEUS_IDLE = 0, + ARKE_ZEUS_ACTIVE = (1 << 0), ARKE_ZEUS_CLIMATE_UNCONTROLLED_WD = (1 << 1), - ARKE_ZEUS_HUMIDITY_UNREACHABLE = (1 << 2), + ARKE_ZEUS_HUMIDITY_UNREACHABLE = (1 << 2), ARKE_ZEUS_TEMPERATURE_UNREACHABLE = (1 << 3), } ArkeZeusStatus_e; struct ArkeZeusStatus_t { ArkeZeusStatus_e Status; ArkeFanStatus Fan[2]; } __attribute__((packed)); typedef struct ArkeZeusStatus_t ArkeZeusStatus; struct ArkeZeusControlPoint_t { int16_t Humidity; int16_t Temperature; } __attribute__((packed)); typedef struct ArkeZeusControlPoint_t ArkeZeusControlPoint; struct ArkeHeliosSetPoint_t { uint8_t Visible; uint8_t UV; } __attribute__((packed)); typedef struct ArkeHeliosSetPoint_t ArkeHeliosSetPoint; struct ArkeCelaenoSetPoint_t { uint8_t Power; } __attribute__((packed)); typedef struct ArkeCelaenoSetPoint_t ArkeCelaenoSetPoint; struct ArkeCelaenoStatus_t { uint8_t waterLevel; ArkeFanStatus fanStatus; } __attribute__((packed)); typedef struct ArkeCelaenoStatus_t ArkeCelaenoStatus; typedef enum ArkeCelaenoWaterLevel_e { ARKE_CELAENO_NOMINAL = 0, ARKE_CELAENO_WARNING = (1 << 0), ARKE_CELAENO_CRITICAL = (1 << 1), ARKE_CELAENO_RO_ERROR = (1 << 2) } ArkeCelaenoWaterLevel; #define ArkeCelaenoWaterNominal(status) ( (status).waterLevel == 0 ) #define ArkeCelaenoWaterWarning(status) ( (status).waterLevel == ARKE_CELAENO_WARNING ) #define ArkeCelaenoWaterCritical(status) ( ((status).waterLevel & ~(ARKE_CELAENO_CRITICAL | ARKE_CELAENO_RO_ERROR) ) == ARKE_CELAENO_WARNING ) #define ArkeCelaenoWaterHasRoError(status) (((status).waterLevel & ARKE_CELAENO_RO_ERROR) != 0x00) struct ArkeCelaenoConfig_t { uint16_t RampUpTimeMS; uint16_t RampDownTimeMS; uint16_t MinOnTimeMS; uint16_t DebounceTimeMS; } __attribute__((packed)); typedef struct ArkeCelaenoConfig_t ArkeCelaenoConfig; #ifdef __cplusplus } #endif //__cplusplus diff --git a/src-go/arke/pd_config.go b/src-go/arke/pid_config.go similarity index 100% rename from src-go/arke/pd_config.go rename to src-go/arke/pid_config.go diff --git a/src-go/arke/zeus.go b/src-go/arke/zeus.go index fc97e75..6f147d4 100644 --- a/src-go/arke/zeus.go +++ b/src-go/arke/zeus.go @@ -1,166 +1,170 @@ package arke import ( "encoding/binary" "fmt" "math" ) type ZeusSetPoint struct { Humidity float32 Temperature float32 Wind uint8 } func (m *ZeusSetPoint) MessageClassID() MessageClass { return ZeusSetPointMessage } func checkSize(buf []byte, expected int) error { if len(buf) < expected { return fmt.Errorf("Invalid buffer size %d, required %d", len(buf), expected) } return nil } func (m ZeusSetPoint) Marshall(buf []byte) (int, error) { if err := checkSize(buf, 5); err != nil { return 0, err } binary.LittleEndian.PutUint16(buf[0:], humidityFloatToBinary(m.Humidity)) binary.LittleEndian.PutUint16(buf[2:], hih6030TemperatureFloatToBinary(m.Temperature)) buf[4] = m.Wind return 5, nil } func (m *ZeusSetPoint) Unmarshall(buf []byte) error { if err := checkSize(buf, 5); err != nil { return err } m.Humidity = humidityBinaryToFloat(binary.LittleEndian.Uint16(buf[0:])) if math.IsNaN(float64(m.Humidity)) == true { return fmt.Errorf("Invalid humidity value") } m.Temperature = hih6030TemperatureBinaryToFloat(binary.LittleEndian.Uint16(buf[2:])) if math.IsNaN(float64(m.Temperature)) == true { return fmt.Errorf("Invalid temperature value") } m.Wind = buf[4] return nil } type ZeusReport struct { Humidity float32 Temperature [4]float32 } func (m *ZeusReport) MessageClassID() MessageClass { return ZeusReportMessage } func (m *ZeusReport) Unmarshall(buf []byte) error { if err := checkSize(buf, 8); err != nil { return err } packed := []uint16{ binary.LittleEndian.Uint16(buf[0:]), binary.LittleEndian.Uint16(buf[2:]), binary.LittleEndian.Uint16(buf[4:]), binary.LittleEndian.Uint16(buf[6:]), } m.Humidity = humidityBinaryToFloat(packed[0] & 0x3fff) if math.IsNaN(float64(m.Humidity)) == true { return fmt.Errorf("Invalid humidity value") } m.Temperature[0] = hih6030TemperatureBinaryToFloat((packed[0] >> 14) | (packed[1]&0x0fff)<<2) if math.IsNaN(float64(m.Temperature[0])) == true { return fmt.Errorf("Invalid temperature value") } m.Temperature[1] = tmp1075BinaryToFloat((packed[1] >> 12) | (packed[2]&0x00ff)<<4) m.Temperature[2] = tmp1075BinaryToFloat((packed[2] >> 8) | (packed[3]&0x000f)<<8) m.Temperature[3] = tmp1075BinaryToFloat((packed[3] & 0xfff0) >> 4) return nil } type ZeusConfig struct { Humidity PDConfig Temperature PDConfig } func (m *ZeusConfig) MessageClassID() MessageClass { return ZeusConfigMessage } func (m ZeusConfig) Marshall(buf []byte) (int, error) { if err := checkSize(buf, 8); err != nil { return 0, err } if err := m.Humidity.marshall(buf[0:]); err != nil { return 0, err } if err := m.Temperature.marshall(buf[4:]); err != nil { return 4, err } return 8, nil } func (m *ZeusConfig) Unmarshall(buf []byte) error { if err := checkSize(buf, 8); err != nil { return err } m.Humidity.unmarshall(buf[0:]) m.Temperature.unmarshall(buf[4:]) return nil } +type ZeusStatusValue uint8 + const ( - ZeusIdle uint8 = 0x00 - ZeusActive uint8 = 0x01 - ZeusClimateNotControlledWatchDog uint8 = 0x02 + ZeusIdle ZeusStatusValue = 0x00 + ZeusActive ZeusStatusValue = 1 << 0 + ZeusClimateNotControlledWatchDog ZeusStatusValue = 1 << 1 + ZeusHumidityUnreachable ZeusStatusValue = 1 << 2 + ZeusTemperatureUnreachable ZeusStatusValue = 1 << 3 ) type ZeusStatus struct { - Status uint8 + Status ZeusStatusValue Fans [2]FanStatusAndRPM } func (m *ZeusStatus) MessageClassID() MessageClass { return ZeusStatusMessage } func (m *ZeusStatus) Unmarshall(buf []byte) error { if err := checkSize(buf, 5); err != nil { return err } - m.Status = buf[0] + m.Status = ZeusStatusValue(buf[0]) m.Fans[0] = FanStatusAndRPM(binary.LittleEndian.Uint16(buf[1:])) m.Fans[1] = FanStatusAndRPM(binary.LittleEndian.Uint16(buf[3:])) return nil } type ZeusControlPoint struct { Humidity int16 Temperature int16 } func (m *ZeusControlPoint) MessageClassID() MessageClass { return ZeusControlPointMessage } func (m *ZeusControlPoint) Unmarshall(buf []byte) error { if err := checkSize(buf, 4); err != nil { return err } m.Humidity = int16(binary.LittleEndian.Uint16(buf[0:])) m.Temperature = int16(binary.LittleEndian.Uint16(buf[2:])) return nil } func init() { messageFactory[ZeusSetPointMessage] = func() ReceivableMessage { return &ZeusSetPoint{} } messageFactory[ZeusReportMessage] = func() ReceivableMessage { return &ZeusReport{} } messageFactory[ZeusConfigMessage] = func() ReceivableMessage { return &ZeusConfig{} } messageFactory[ZeusStatusMessage] = func() ReceivableMessage { return &ZeusStatus{} } messageFactory[ZeusControlPointMessage] = func() ReceivableMessage { return &ZeusControlPoint{} } }