github.com/simpleiot/simpleiot@v0.18.3/node/node.go (about) 1 package node 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "log" 8 "text/template" 9 "time" 10 11 "github.com/nats-io/nats.go" 12 13 "github.com/simpleiot/simpleiot/client" 14 "github.com/simpleiot/simpleiot/data" 15 "github.com/simpleiot/simpleiot/system" 16 ) 17 18 // Manager is responsible for maintaining node state, running rules, etc 19 type Manager struct { 20 nc *nats.Conn 21 appVersion string 22 osVersionField string 23 modbusManager *ModbusManager 24 rootNodeID string 25 oneWireManager *oneWireManager 26 chStop chan struct{} 27 } 28 29 // NewManger creates a new Manager 30 func NewManger(nc *nats.Conn, appVersion, osVersionField string) *Manager { 31 return &Manager{ 32 nc: nc, 33 appVersion: appVersion, 34 osVersionField: osVersionField, 35 chStop: make(chan struct{}), 36 } 37 } 38 39 // Init initializes some node managers 40 func (m *Manager) init() error { 41 var rootNode data.NodeEdge 42 43 rootNodes, err := client.GetNodes(m.nc, "root", "all", "", false) 44 45 if err != nil { 46 return fmt.Errorf("Error getting root node: %v", err) 47 } 48 49 if len(rootNodes) > 0 { 50 rootNode = rootNodes[0] 51 } else { 52 return fmt.Errorf("No nodes returned for root node") 53 } 54 55 m.rootNodeID = rootNode.ID 56 57 appVer, ok := rootNode.Points.Find(data.PointTypeVersionApp, "") 58 if !ok || appVer.Text != m.appVersion { 59 log.Println("Setting app version:", m.appVersion) 60 err := client.SendNodePoint(m.nc, rootNode.ID, data.Point{ 61 Type: data.PointTypeVersionApp, 62 Text: m.appVersion, 63 }, true) 64 65 if err != nil { 66 log.Println("Error setting app version") 67 } 68 } 69 70 // check if OS version is current 71 osVer, err := system.ReadOSVersion(m.osVersionField) 72 if err != nil { 73 log.Println("Error reading OS version:", err) 74 } else { 75 log.Println("OS version:", osVer) 76 osVerStored, ok := rootNode.Points.Find(data.PointTypeVersionOS, "") 77 if !ok || osVer.String() != osVerStored.Text { 78 log.Println("Setting os version:", osVer) 79 err := client.SendNodePoint(m.nc, rootNode.ID, data.Point{ 80 Type: data.PointTypeVersionOS, 81 Text: osVer.String(), 82 }, true) 83 84 if err != nil { 85 log.Println("Error setting OS version") 86 } 87 } 88 89 } 90 91 m.modbusManager = NewModbusManager(m.nc, m.rootNodeID) 92 m.oneWireManager = newOneWireManager(m.nc, m.rootNodeID) 93 94 return nil 95 } 96 97 // Start manager 98 func (m *Manager) Start() error { 99 if err := m.init(); err != nil { 100 return fmt.Errorf("Error initializing nodes: %v", err) 101 } 102 103 t := time.NewTimer(time.Millisecond) 104 105 // TODO: this will not scale and needs to be made event driven 106 // on the creation of new nodes 107 for { 108 select { 109 case <-m.chStop: 110 return errors.New("node manager stopping") 111 case <-t.C: 112 if m.modbusManager != nil { 113 _ = m.modbusManager.Update() 114 } 115 if m.oneWireManager != nil { 116 _ = m.oneWireManager.update() 117 } 118 t.Reset(time.Second * 20) 119 } 120 } 121 122 /* the following code needs redone, so commenting out for now 123 for { 124 // TODO: this will not scale and needs to be made event driven 125 nodes, err := m.db.Nodes() 126 if err != nil { 127 log.Println("Error getting nodes:", err) 128 time.Sleep(10 * time.Second) 129 continue 130 } 131 132 for _, node := range nodes { 133 // update node state 134 state, changed := node.GetState() 135 if changed { 136 p := data.Point{ 137 Time: time.Now(), 138 Type: data.PointTypeSysState, 139 Text: state, 140 } 141 142 err := client.SendNodePoint(m.nc, node.ID, p, false) 143 if err != nil { 144 log.Println("Error updating node state:", err) 145 } 146 } 147 } 148 149 time.Sleep(30 * time.Second) 150 } 151 */ 152 } 153 154 // Stop manager 155 func (m *Manager) Stop(_ error) { 156 close(m.chStop) 157 } 158 159 type nodeTemplateData struct { 160 ID string 161 Description string 162 Ios map[string]float64 163 } 164 165 func renderNotifyTemplate(node *data.Node, msgTemplate string) (string, error) { 166 // build map of IO values so they are easy to reference by type or ID in template 167 dtd := nodeTemplateData{ 168 ID: node.ID, 169 Description: node.Desc(), 170 Ios: make(map[string]float64), 171 } 172 173 for _, io := range node.Points { 174 if io.Type != "" { 175 dtd.Ios[io.Type] = io.Value 176 } 177 } 178 179 buf := new(bytes.Buffer) 180 181 tmpl, err := template.New("msg").Parse(msgTemplate) 182 183 if err != nil { 184 return "", err 185 } 186 187 err = tmpl.Execute(buf, dtd) 188 189 if err != nil { 190 return "", err 191 } 192 193 return buf.String(), nil 194 195 }