mirror of
https://github.com/jpeletier/koolnova2mqtt.git
synced 2026-01-11 15:11:43 +00:00
refactoring
This commit is contained in:
203
kn/bridge.go
Normal file
203
kn/bridge.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package kn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"koolnova2mqtt/watcher"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Publish func(topic string, qos byte, retained bool, payload string)
|
||||
|
||||
type Config struct {
|
||||
ModuleName string
|
||||
SlaveID byte
|
||||
Publish Publish
|
||||
TopicPrefix string
|
||||
ReadRegister watcher.ReadRegister
|
||||
}
|
||||
|
||||
type Bridge struct {
|
||||
Config
|
||||
zw *watcher.Watcher
|
||||
sysw *watcher.Watcher
|
||||
refresh func()
|
||||
}
|
||||
|
||||
func getActiveZones(w Watcher) ([]*Zone, error) {
|
||||
var zones []*Zone
|
||||
|
||||
for n := 0; n < NUM_ZONES; n++ {
|
||||
zone := NewZone(&ZoneConfig{
|
||||
ZoneNumber: n,
|
||||
Watcher: w,
|
||||
})
|
||||
isPresent, err := zone.IsPresent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isPresent {
|
||||
zones = append(zones, zone)
|
||||
temp, _ := zone.GetCurrentTemperature()
|
||||
fmt.Printf("Zone %d is present. Temperature %g ºC\n", zone.ZoneNumber, temp)
|
||||
}
|
||||
}
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
func NewBridge(config *Config) *Bridge {
|
||||
|
||||
zw := watcher.New(&watcher.Config{
|
||||
Address: FIRST_ZONE_REGISTER,
|
||||
Quantity: TOTAL_ZONE_REGISTERS,
|
||||
RegisterSize: 2,
|
||||
SlaveID: config.SlaveID,
|
||||
Read: config.ReadRegister,
|
||||
})
|
||||
|
||||
sysw := watcher.New(&watcher.Config{
|
||||
Address: FIRST_SYS_REGISTER,
|
||||
Quantity: TOTAL_SYS_REGISTERS,
|
||||
RegisterSize: 2,
|
||||
SlaveID: config.SlaveID,
|
||||
Read: config.ReadRegister,
|
||||
})
|
||||
|
||||
b := &Bridge{
|
||||
Config: *config,
|
||||
zw: zw,
|
||||
sysw: sysw,
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bridge) Start() {
|
||||
sys := NewSys(&SysConfig{
|
||||
Watcher: b.sysw,
|
||||
})
|
||||
|
||||
err := b.zw.Poll()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = b.sysw.Poll()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
zones, err := getActiveZones(b.zw)
|
||||
|
||||
for _, zone := range zones {
|
||||
zone := zone
|
||||
zone.OnCurrentTempChange = func(currentTemp float32) {
|
||||
b.Publish(b.getZoneTopic(zone.ZoneNumber, "currentTemp"), 0, false, fmt.Sprintf("%g", currentTemp))
|
||||
}
|
||||
zone.OnTargetTempChange = func(targetTemp float32) {
|
||||
b.Publish(b.getZoneTopic(zone.ZoneNumber, "targetTemp"), 0, false, fmt.Sprintf("%g", targetTemp))
|
||||
}
|
||||
zone.OnFanModeChange = func(fanMode FanMode) {
|
||||
b.Publish(b.getZoneTopic(zone.ZoneNumber, "fanMode"), 0, false, FanMode2Str(fanMode))
|
||||
}
|
||||
zone.OnHvacModeChange = func(hvacMode HvacMode) {
|
||||
b.Publish(b.getZoneTopic(zone.ZoneNumber, "hvacMode"), 0, false, HvacMode2Str(hvacMode))
|
||||
}
|
||||
}
|
||||
|
||||
sys.OnACAirflowChange = func(ac ACMachine) {
|
||||
airflow, err := sys.GetAirflow(ac)
|
||||
if err != nil {
|
||||
log.Printf("Error reading airflow of AC %d: %s", ac, err)
|
||||
return
|
||||
}
|
||||
b.Publish(b.getACTopic(ac, "airflow"), 0, false, strconv.Itoa(airflow))
|
||||
}
|
||||
sys.OnACTargetTempChange = func(ac ACMachine) {
|
||||
targetTemp, err := sys.GetMachineTargetTemp(ac)
|
||||
if err != nil {
|
||||
log.Printf("Error reading target temp of AC %d: %s", ac, err)
|
||||
return
|
||||
}
|
||||
b.Publish(b.getACTopic(ac, "targetTemp"), 0, false, fmt.Sprintf("%g", targetTemp))
|
||||
}
|
||||
sys.OnACTargetFanModeChange = func(ac ACMachine) {
|
||||
targetAirflow, err := sys.GetTargetFanMode(ac)
|
||||
if err != nil {
|
||||
log.Printf("Error reading target airflow of AC %d: %s", ac, err)
|
||||
return
|
||||
}
|
||||
b.Publish(b.getACTopic(ac, "fanMode"), 0, false, FanMode2Str(targetAirflow))
|
||||
}
|
||||
sys.OnEfficiencyChange = func() {
|
||||
efficiency, err := sys.GetEfficiency()
|
||||
if err != nil {
|
||||
log.Printf("Error reading efficiency value: %s", err)
|
||||
return
|
||||
}
|
||||
b.Publish(b.getSysTopic("efficiency"), 0, false, strconv.Itoa(efficiency))
|
||||
}
|
||||
sys.OnSystemEnabledChange = func() {
|
||||
enabled, err := sys.GetSystemEnabled()
|
||||
if err != nil {
|
||||
log.Printf("Error reading enabled value: %s", err)
|
||||
return
|
||||
}
|
||||
b.Publish(b.getSysTopic("enabled"), 0, false, fmt.Sprintf("%t", enabled))
|
||||
}
|
||||
sys.OnHvacModeChange = func() {
|
||||
mode, err := sys.GetSystemHVACMode()
|
||||
if err != nil {
|
||||
log.Printf("Error reading hvac mode: %s", err)
|
||||
return
|
||||
}
|
||||
b.Publish(b.getSysTopic("hvacMode"), 0, false, HvacMode2Str(mode))
|
||||
}
|
||||
|
||||
b.zw.TriggerCallbacks()
|
||||
b.sysw.TriggerCallbacks()
|
||||
|
||||
bauds, err := sys.GetBaudRate()
|
||||
if err != nil {
|
||||
log.Printf("Error reading configured serial baud rate: %s", err)
|
||||
}
|
||||
parity, err := sys.GetParity()
|
||||
if err != nil {
|
||||
log.Printf("Error reading configured serial parity: %s", err)
|
||||
}
|
||||
slaveID, err := sys.GetSlaveID()
|
||||
if err != nil {
|
||||
log.Printf("Error reading configured modbus slave ID: %s", err)
|
||||
}
|
||||
b.Publish(b.getSysTopic("serialBaud"), 0, false, strconv.Itoa(bauds))
|
||||
b.Publish(b.getSysTopic("serialParity"), 0, false, parity)
|
||||
b.Publish(b.getSysTopic("slaveId"), 0, false, strconv.Itoa(slaveID))
|
||||
}
|
||||
|
||||
func (b *Bridge) Tick() {
|
||||
err := b.zw.Poll()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = b.sysw.Poll()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bridge) getZoneTopic(zoneNum int, subtopic string) string {
|
||||
return fmt.Sprintf("%s/%s/zone%d/%s", b.TopicPrefix, b.ModuleName, zoneNum, subtopic)
|
||||
}
|
||||
|
||||
func (b *Bridge) getSysTopic(subtopic string) string {
|
||||
return fmt.Sprintf("%s/%s/sys/%s", b.TopicPrefix, b.ModuleName, subtopic)
|
||||
}
|
||||
|
||||
func (b *Bridge) getACTopic(ac ACMachine, subtopic string) string {
|
||||
return b.getSysTopic(fmt.Sprintf("ac%d/%s", ac, subtopic))
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package kn
|
||||
|
||||
import "koolnova2mqtt/bimap"
|
||||
|
||||
const NUM_ZONES = 16
|
||||
|
||||
const REG_PER_ZONE = 4
|
||||
const REG_ENABLED = 1
|
||||
const REG_MODE = 2
|
||||
@@ -17,6 +19,11 @@ const REG_EFFICIENCY = 79
|
||||
const REG_SYSTEM_ENABLED = 81
|
||||
const REG_SYS_HVAC_MODE = 82
|
||||
|
||||
const FIRST_ZONE_REGISTER = REG_ENABLED
|
||||
const TOTAL_ZONE_REGISTERS = NUM_ZONES * REG_PER_ZONE
|
||||
const FIRST_SYS_REGISTER = REG_AIRFLOW
|
||||
const TOTAL_SYS_REGISTERS = 18
|
||||
|
||||
type FanMode byte
|
||||
|
||||
const FAN_OFF FanMode = 0
|
||||
|
||||
232
main.go
232
main.go
@@ -9,7 +9,9 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -17,8 +19,6 @@ import (
|
||||
"github.com/goburrow/modbus"
|
||||
)
|
||||
|
||||
const NUM_ZONES = 16
|
||||
|
||||
func buildReader(handler *modbus.RTUClientHandler, client modbus.Client) watcher.ReadRegister {
|
||||
return func(slaveID byte, address uint16, quantity uint16) (results []byte, err error) {
|
||||
handler.SlaveId = slaveID
|
||||
@@ -27,31 +27,23 @@ func buildReader(handler *modbus.RTUClientHandler, client modbus.Client) watcher
|
||||
}
|
||||
}
|
||||
|
||||
func getActiveZones(w kn.Watcher) ([]*kn.Zone, error) {
|
||||
var zones []*kn.Zone
|
||||
|
||||
for n := 0; n < NUM_ZONES; n++ {
|
||||
zone := kn.NewZone(&kn.ZoneConfig{
|
||||
ZoneNumber: n,
|
||||
Watcher: w,
|
||||
})
|
||||
isPresent, err := zone.IsPresent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isPresent {
|
||||
zones = append(zones, zone)
|
||||
temp, _ := zone.GetCurrentTemperature()
|
||||
fmt.Printf("Zone %d is present. Temperature %g ºC\n", zone.ZoneNumber, temp)
|
||||
}
|
||||
func generateNodeName(slaveID string, port string) string {
|
||||
reg, err := regexp.Compile("[^a-zA-Z0-9]+")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return zones, nil
|
||||
hostname, _ := os.Hostname()
|
||||
|
||||
port = strings.Replace(port, "/dev/", "", -1)
|
||||
port = reg.ReplaceAllString(port, "")
|
||||
return strings.ToLower(fmt.Sprintf("%s_%s_%s", hostname, port, slaveID))
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
ctrlC := make(chan os.Signal, 1)
|
||||
signal.Notify(ctrlC, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
hostname, _ := os.Hostname()
|
||||
|
||||
@@ -62,15 +54,21 @@ func main() {
|
||||
username := flag.String("username", "", "A username to authenticate to the MQTT server")
|
||||
password := flag.String("password", "", "Password to match username")
|
||||
prefix := flag.String("prefix", "koolnova2mqtt", "MQTT topic root where to publish/read topics")
|
||||
modbusPort := flag.String("modbusPort", "/dev/ttyUSB0", "Serial port where modbus hardware is connected")
|
||||
modbusPortBaudRate := flag.Int("modbusRate", 9600, "Modbus port data rate")
|
||||
modbusDataBits := flag.Int("modbusDataBits", 8, "Modbus port data bits")
|
||||
modbusPortParity := flag.String("modbusParity", "E", "N - None, E - Even, O - Odd (default E) (The use of no parity requires 2 stop bits.)")
|
||||
modbusStopBits := flag.Int("modbusStopBits", 1, "Modbus port stop bits")
|
||||
modbusSlaveList := flag.String("modbusSlaveIDs", "49", "Comma-separated list of modbus slave IDs to manage")
|
||||
modbusSlaveNames := flag.String("modbusSlaveNames", "", "Comma-separated list of modbus slave names. Defaults to 'slave#'")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
// Modbus RTU/ASCII
|
||||
handler := modbus.NewRTUClientHandler("/dev/remserial1")
|
||||
handler.BaudRate = 9600
|
||||
handler.DataBits = 8
|
||||
handler.Parity = "E"
|
||||
handler.StopBits = 1
|
||||
handler.SlaveId = 49
|
||||
handler := modbus.NewRTUClientHandler(*modbusPort)
|
||||
handler.BaudRate = *modbusPortBaudRate
|
||||
handler.DataBits = *modbusDataBits
|
||||
handler.Parity = *modbusPortParity
|
||||
handler.StopBits = *modbusStopBits
|
||||
handler.Timeout = 5 * time.Second
|
||||
|
||||
err := handler.Connect()
|
||||
@@ -79,57 +77,46 @@ func main() {
|
||||
}
|
||||
defer handler.Close()
|
||||
|
||||
client := modbus.NewClient(handler)
|
||||
modbusClient := modbus.NewClient(handler)
|
||||
|
||||
nodeName := "topFloors"
|
||||
registerReader := buildReader(handler, modbusClient)
|
||||
|
||||
getZoneTopic := func(zoneNum int, subtopic string) string {
|
||||
return fmt.Sprintf("%s/%s/zone%d/%s", *prefix, nodeName, zoneNum, subtopic)
|
||||
var mqttClient MQTT.Client
|
||||
publish := func(topic string, qos byte, retained bool, payload string) {
|
||||
mqttClient.Publish(topic, qos, retained, payload)
|
||||
}
|
||||
|
||||
getSysTopic := func(subtopic string) string {
|
||||
return fmt.Sprintf("%s/%s/sys/%s", *prefix, nodeName, subtopic)
|
||||
var snameList []string
|
||||
slist := strings.Split(*modbusSlaveList, ",")
|
||||
|
||||
if *modbusSlaveNames == "" {
|
||||
for _, slaveIDStr := range slist {
|
||||
snameList = append(snameList, generateNodeName(slaveIDStr, *modbusPort))
|
||||
}
|
||||
} else {
|
||||
snameList = strings.Split(*modbusSlaveNames, ",")
|
||||
if len(slist) != len(snameList) {
|
||||
log.Fatalf("modbusSlaveIDs and modbusSlaveNames lists must have the same length")
|
||||
}
|
||||
}
|
||||
|
||||
getACTopic := func(ac kn.ACMachine, subtopic string) string {
|
||||
return getSysTopic(fmt.Sprintf("ac%d/%s", ac, subtopic))
|
||||
var bridges []*kn.Bridge
|
||||
for i, slaveIDStr := range slist {
|
||||
slaveID, err := strconv.Atoi(slaveIDStr)
|
||||
slaveName := snameList[i]
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing slaveID list")
|
||||
}
|
||||
bridge := kn.NewBridge(&kn.Config{
|
||||
ModuleName: slaveName,
|
||||
SlaveID: byte(slaveID),
|
||||
Publish: publish,
|
||||
TopicPrefix: *prefix,
|
||||
ReadRegister: registerReader,
|
||||
})
|
||||
bridges = append(bridges, bridge)
|
||||
}
|
||||
|
||||
registerReader := buildReader(handler, client)
|
||||
|
||||
zw := watcher.New(&watcher.Config{
|
||||
Address: 1,
|
||||
Quantity: 64,
|
||||
RegisterSize: 2,
|
||||
SlaveID: 49,
|
||||
Read: registerReader,
|
||||
})
|
||||
|
||||
sysw := watcher.New(&watcher.Config{
|
||||
Address: kn.REG_AIRFLOW,
|
||||
Quantity: 18,
|
||||
RegisterSize: 2,
|
||||
SlaveID: 49,
|
||||
Read: registerReader,
|
||||
})
|
||||
|
||||
err = zw.Poll()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = sysw.Poll()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
zones, err := getActiveZones(zw)
|
||||
sys := kn.NewSys(&kn.SysConfig{
|
||||
Watcher: sysw,
|
||||
})
|
||||
|
||||
connOpts := MQTT.NewClientOptions().AddBroker(*server).SetClientID(*clientid).SetCleanSession(true)
|
||||
if *username != "" {
|
||||
connOpts.SetUsername(*username)
|
||||
@@ -139,96 +126,13 @@ func main() {
|
||||
}
|
||||
tlsConfig := &tls.Config{InsecureSkipVerify: true, ClientAuth: tls.NoClientCert}
|
||||
connOpts.SetTLSConfig(tlsConfig)
|
||||
|
||||
connOpts.OnConnect = func(c MQTT.Client) {
|
||||
/* if token := c.Subscribe(*topic, byte(*qos), onMessageReceived); token.Wait() && token.Error() != nil {
|
||||
panic(token.Error())
|
||||
} */
|
||||
zw.TriggerCallbacks()
|
||||
sysw.TriggerCallbacks()
|
||||
bauds, err := sys.GetBaudRate()
|
||||
if err != nil {
|
||||
log.Printf("Error reading configured serial baud rate: %s", err)
|
||||
}
|
||||
parity, err := sys.GetParity()
|
||||
if err != nil {
|
||||
log.Printf("Error reading configured serial parity: %s", err)
|
||||
}
|
||||
slaveID, err := sys.GetSlaveID()
|
||||
if err != nil {
|
||||
log.Printf("Error reading configured modbus slave ID: %s", err)
|
||||
}
|
||||
c.Publish(getSysTopic("serialBaud"), 0, false, strconv.Itoa(bauds))
|
||||
c.Publish(getSysTopic("serialParity"), 0, false, parity)
|
||||
c.Publish(getSysTopic("slaveId"), 0, false, slaveID)
|
||||
|
||||
}
|
||||
mqttClient := MQTT.NewClient(connOpts)
|
||||
|
||||
for _, zone := range zones {
|
||||
zone := zone
|
||||
zone.OnCurrentTempChange = func(currentTemp float32) {
|
||||
mqttClient.Publish(getZoneTopic(zone.ZoneNumber, "currentTemp"), 0, false, fmt.Sprintf("%g", currentTemp))
|
||||
}
|
||||
zone.OnTargetTempChange = func(targetTemp float32) {
|
||||
mqttClient.Publish(getZoneTopic(zone.ZoneNumber, "targetTemp"), 0, false, fmt.Sprintf("%g", targetTemp))
|
||||
}
|
||||
zone.OnFanModeChange = func(fanMode kn.FanMode) {
|
||||
mqttClient.Publish(getZoneTopic(zone.ZoneNumber, "fanMode"), 0, false, kn.FanMode2Str(fanMode))
|
||||
}
|
||||
zone.OnHvacModeChange = func(hvacMode kn.HvacMode) {
|
||||
mqttClient.Publish(getZoneTopic(zone.ZoneNumber, "hvacMode"), 0, false, kn.HvacMode2Str(hvacMode))
|
||||
for _, b := range bridges {
|
||||
b.Start()
|
||||
}
|
||||
}
|
||||
|
||||
sys.OnACAirflowChange = func(ac kn.ACMachine) {
|
||||
airflow, err := sys.GetAirflow(ac)
|
||||
if err != nil {
|
||||
log.Printf("Error reading airflow of AC %d: %s", ac, err)
|
||||
return
|
||||
}
|
||||
mqttClient.Publish(getACTopic(ac, "airflow"), 0, false, strconv.Itoa(airflow))
|
||||
}
|
||||
sys.OnACTargetTempChange = func(ac kn.ACMachine) {
|
||||
targetTemp, err := sys.GetMachineTargetTemp(ac)
|
||||
if err != nil {
|
||||
log.Printf("Error reading target temp of AC %d: %s", ac, err)
|
||||
return
|
||||
}
|
||||
mqttClient.Publish(getACTopic(ac, "targetTemp"), 0, false, fmt.Sprintf("%g", targetTemp))
|
||||
}
|
||||
sys.OnACTargetFanModeChange = func(ac kn.ACMachine) {
|
||||
targetAirflow, err := sys.GetTargetFanMode(ac)
|
||||
if err != nil {
|
||||
log.Printf("Error reading target airflow of AC %d: %s", ac, err)
|
||||
return
|
||||
}
|
||||
mqttClient.Publish(getACTopic(ac, "fanMode"), 0, false, kn.FanMode2Str(targetAirflow))
|
||||
}
|
||||
sys.OnEfficiencyChange = func() {
|
||||
efficiency, err := sys.GetEfficiency()
|
||||
if err != nil {
|
||||
log.Printf("Error reading efficiency value: %s", err)
|
||||
return
|
||||
}
|
||||
mqttClient.Publish(getSysTopic("efficiency"), 0, false, strconv.Itoa(efficiency))
|
||||
}
|
||||
sys.OnSystemEnabledChange = func() {
|
||||
enabled, err := sys.GetSystemEnabled()
|
||||
if err != nil {
|
||||
log.Printf("Error reading enabled value: %s", err)
|
||||
return
|
||||
}
|
||||
mqttClient.Publish(getSysTopic("enabled"), 0, false, fmt.Sprintf("%t", enabled))
|
||||
}
|
||||
sys.OnHvacModeChange = func() {
|
||||
mode, err := sys.GetSystemHVACMode()
|
||||
if err != nil {
|
||||
log.Printf("Error reading hvac mode: %s", err)
|
||||
return
|
||||
}
|
||||
mqttClient.Publish(getSysTopic("hvacMode"), 0, false, kn.HvacMode2Str(mode))
|
||||
}
|
||||
mqttClient = MQTT.NewClient(connOpts)
|
||||
|
||||
if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
|
||||
panic(token.Error())
|
||||
@@ -240,18 +144,12 @@ func main() {
|
||||
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
err := zw.Poll()
|
||||
if err != nil {
|
||||
log.Printf("Error polling zones over modbus: %s\n", err)
|
||||
}
|
||||
|
||||
err = sysw.Poll()
|
||||
if err != nil {
|
||||
log.Printf("Error polling system config over modbus: %s\n", err)
|
||||
for _, b := range bridges {
|
||||
b.Tick()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
<-c
|
||||
<-ctrlC
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type Config struct {
|
||||
RegisterSize int
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
type Watcher struct {
|
||||
Config
|
||||
state []byte
|
||||
callbacks map[uint16]func(address uint16)
|
||||
@@ -25,18 +25,18 @@ var ErrIncorrectRegisterSize = errors.New("Incorrect register size")
|
||||
var ErrAddressOutOfRange = errors.New("Register address out of range")
|
||||
var ErrUninitialized = errors.New("State uninitialized. Call Poll() first.")
|
||||
|
||||
func New(config *Config) *watcher {
|
||||
return &watcher{
|
||||
func New(config *Config) *Watcher {
|
||||
return &Watcher{
|
||||
Config: *config,
|
||||
callbacks: make(map[uint16]func(address uint16)),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) RegisterCallback(address uint16, callback func(address uint16)) {
|
||||
func (w *Watcher) RegisterCallback(address uint16, callback func(address uint16)) {
|
||||
w.callbacks[address] = callback
|
||||
}
|
||||
|
||||
func (w *watcher) Poll() error {
|
||||
func (w *Watcher) Poll() error {
|
||||
newState, err := w.Read(w.SlaveID, w.Address, w.Quantity)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -72,7 +72,7 @@ func (w *watcher) Poll() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *watcher) ReadRegister(address uint16) (value []byte, err error) {
|
||||
func (w *Watcher) ReadRegister(address uint16) (value []byte, err error) {
|
||||
if address < w.Address || address > w.Address+uint16(w.Quantity) {
|
||||
return nil, ErrAddressOutOfRange
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (w *watcher) ReadRegister(address uint16) (value []byte, err error) {
|
||||
|
||||
}
|
||||
|
||||
func (w *watcher) TriggerCallbacks() {
|
||||
func (w *Watcher) TriggerCallbacks() {
|
||||
for address, callback := range w.callbacks {
|
||||
callback(address)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user