package device import ( "errors" "time" "src.dualinventive.com/go/cp3000-interface/internal/statusupdate" "src.dualinventive.com/go/dinet/rpc" "src.dualinventive.com/go/lib/cp3000" ) // CrtmGateway is a ZKL 3000 RC device type CrtmGateway struct { *Base children map[string]*cp3000.ChildRouter versionKeyFW rpc.VersionKey versionKeyHW rpc.VersionKey } func (z *CrtmGateway) construct() { z.children = make(map[string]*cp3000.ChildRouter) z.decoder = statusupdate.NewUpdateDecoder(z.dev.Logger()) z.dev.Subscribe(rpc.ClassMethodSensorInfo, rpc.MsgTypeRequest, z.sensorInfo) z.dev.AddConfig(rpc.ConfigEndpoint, z.configGetEndpoint, z.configSetEndpoint, nil) } func (z *CrtmGateway) init() { } // Close closes the connection to DI-Net and also for its children func (z *CrtmGateway) Close() error { for _, dev := range z.children { if err := dev.Close(); err != nil { z.dev.Logger().WithError(err).Warning("cannot close child") } } return z.Base.Close() } // Statusupdate is a callback for the status message // Suppress the linter because statusUpdateCmd needs to satisfy the interface //nolint: unparam func (z *CrtmGateway) statusUpdateCmd(r cp3000.Router, args []string) error { old := z.decoder.StatusUpdate() err := z.decoder.Decode(args) if err != nil { z.dev.Logger().WithError(err).Warning("status-decoder failed") return nil } s := z.decoder.StatusUpdate() data := []*rpc.ResultValueItem{} data = old.CheckBattery1(data, s) data = old.CheckBattery1State(data, s) data = old.CheckRSSI(data, s) data = old.CheckBER(data, s) data = old.CheckCRTMTemperature1(data, s) if len(data) > 0 { z.dev.Logger().WithField("count", len(data)).Debug("send sensor data") err = z.dev.Send(&rpc.Msg{ ClassMethod: rpc.ClassMethodSensorData, Type: rpc.MsgTypePublish, Result: rpc.NewResult(data), }) } if pErr := z.dev.SendDeviceData(); pErr != nil { return pErr } return err } func (z *CrtmGateway) gatewayCmd(r cp3000.Router, args []string) error { // We need at least the IMEI and a command if len(args[0]) > 2 { c, ok := z.children[args[0]] if !ok { var err error z.dev.Logger().WithField("imei", args[0]).Info("registering child") c = cp3000.NewChildRouter(z.dev.Logger(), args[0], r) child, err := Register(z.dev, z.Base.repo, c, args[0]) if err != nil { return err } if err := child.RegisterCallbacks(); err != nil { return err } z.children[args[0]] = c } return c.ChildCommand(cp3000.Command(args[1]), args[2:]...) } return errors.New("invalid usage") } // Versions returns the firmware and hardware versions func (z *CrtmGateway) Versions() (rpc.VersionMap, rpc.ErrorCode) { wcpu, rpcerr := z.requestVersion("FW-WCPU") if rpcerr != rpc.Ok { return nil, rpcerr } return rpc.VersionMap{ z.versionKeyFW: wcpu, z.versionKeyHW: z.hwVersion, }, rpc.Ok } // TimeoutDuration returns when the device should be considered offline func (z *CrtmGateway) TimeoutDuration() time.Duration { return time.Minute } // Transport returns the transportation type func (z *CrtmGateway) Transport() (interface{}, rpc.ErrorCode) { return z.cp3000Transport() } // sensorInfo returns all the sensor information func (z *CrtmGateway) sensorInfo(req *rpc.Msg) *rpc.Msg { rep := req.CreateReply() rep.Result = rpc.NewResult([]rpc.ResultInfoItem{ rpc.SensorBattery1Voltage.Info(), rpc.SensorBattery1State.Info(), rpc.SensorRSSI.Info(), rpc.SensorBER.Info(), rpc.GatewaySensorTemperature1.Info(), }) return rep } // RegisterCallbacks registers additional callbacks for CRTM 3000 devices once they authenticated func (z *CrtmGateway) RegisterCallbacks() error { z.client.Register(cp3000.CommandWatchdog, z.heartbeatCmd) z.client.Register(cp3000.CommandGateway, z.gatewayCmd) z.client.Register(cp3000.CommandUpdate, z.statusUpdateCmd) z.client.Register(cp3000.CommandSync, z.syncCmd) z.client.Register(cp3000.CommandExit, z.exitCmd) return nil }