github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/zigbee2mqtt/zigbee2mqtt.go (about) 1 // This file is part of the Smart Home 2 // Program complex distribution https://github.com/e154/smart-home 3 // Copyright (C) 2016-2023, Filippov Alex 4 // 5 // This library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 3 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Library General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library. If not, see 17 // <https://www.gnu.org/licenses/>. 18 19 package zigbee2mqtt 20 21 import ( 22 "context" 23 "sync" 24 25 "github.com/e154/smart-home/common/events" 26 "github.com/e154/smart-home/system/bus" 27 28 "github.com/e154/smart-home/common/apperr" 29 30 "github.com/e154/smart-home/common/logger" 31 32 "github.com/e154/smart-home/adaptors" 33 "github.com/e154/smart-home/common" 34 m "github.com/e154/smart-home/models" 35 "github.com/e154/smart-home/system/mqtt" 36 "go.uber.org/atomic" 37 "go.uber.org/fx" 38 ) 39 40 var ( 41 log = logger.MustGetLogger("zigbee2mqtt") 42 ) 43 44 // zigbee2mqtt ... 45 type zigbee2mqtt struct { 46 mqtt mqtt.MqttServ 47 adaptors *adaptors.Adaptors 48 isStarted *atomic.Bool 49 bridgesLock *sync.Mutex 50 bridges map[int64]*Bridge 51 eventBus bus.Bus 52 } 53 54 // NewZigbee2mqtt ... 55 func NewZigbee2mqtt(lc fx.Lifecycle, 56 mqtt mqtt.MqttServ, 57 adaptors *adaptors.Adaptors, 58 eventBus bus.Bus) Zigbee2mqtt { 59 zigbee2mqtt := &zigbee2mqtt{ 60 mqtt: mqtt, 61 adaptors: adaptors, 62 bridgesLock: &sync.Mutex{}, 63 bridges: make(map[int64]*Bridge), 64 eventBus: eventBus, 65 isStarted: atomic.NewBool(false), 66 } 67 68 lc.Append(fx.Hook{ 69 OnStart: zigbee2mqtt.Start, 70 OnStop: zigbee2mqtt.Shutdown, 71 }) 72 return zigbee2mqtt 73 } 74 75 // Start ... 76 func (z *zigbee2mqtt) Start(ctx context.Context) (err error) { 77 if z.isStarted.Load() { 78 return 79 } 80 z.isStarted.Store(true) 81 82 models, _, err := z.adaptors.Zigbee2mqtt.List(ctx, 99, 0) 83 if err != nil { 84 log.Error(err.Error()) 85 } 86 87 if len(models) == 0 { 88 model := &m.Zigbee2mqtt{ 89 Name: "zigbee2mqtt", 90 BaseTopic: "zigbee2mqtt", 91 PermitJoin: true, 92 } 93 model.Id, err = z.adaptors.Zigbee2mqtt.Add(ctx, model) 94 if err != nil { 95 log.Error(err.Error()) 96 return 97 } 98 models = append(models, model) 99 } 100 101 if err := z.mqtt.Authenticator().Register(z.Authenticator); err != nil { 102 log.Error(err.Error()) 103 } 104 105 //todo fix race condition 106 for _, model := range models { 107 bridge := NewBridge(z.mqtt, z.adaptors, model) 108 bridge.Start() 109 110 z.bridgesLock.Lock() 111 z.bridges[model.Id] = bridge 112 z.bridgesLock.Unlock() 113 } 114 115 _ = z.eventBus.Subscribe("system/models/zigbee2mqtt/+", z.eventHandler) 116 117 z.eventBus.Publish("system/services/zigbee2mqtt", events.EventServiceStarted{Service: "Zigbee2mqtt"}) 118 119 return 120 } 121 122 // Shutdown ... 123 func (z *zigbee2mqtt) Shutdown(ctx context.Context) (err error) { 124 if !z.isStarted.Load() { 125 return 126 } 127 z.isStarted.Store(false) 128 for _, bridge := range z.bridges { 129 bridge.Stop(context.Background()) 130 } 131 _ = z.mqtt.Authenticator().Unregister(z.Authenticator) 132 133 _ = z.eventBus.Unsubscribe("system/models/zigbee2mqtt/+", z.eventHandler) 134 135 z.eventBus.Publish("system/services/zigbee2mqtt", events.EventServiceStopped{Service: "Zigbee2mqtt"}) 136 137 return 138 } 139 140 // AddBridge ... 141 func (z *zigbee2mqtt) AddBridge(model *m.Zigbee2mqtt) (err error) { 142 143 z.bridgesLock.Lock() 144 defer z.bridgesLock.Unlock() 145 146 bridge := NewBridge(z.mqtt, z.adaptors, model) 147 bridge.Start() 148 z.bridges[model.Id] = bridge 149 return 150 } 151 152 // GetBridgeInfo ... 153 func (z *zigbee2mqtt) GetBridgeInfo(id int64) (*m.Zigbee2mqttInfo, error) { 154 z.bridgesLock.Lock() 155 defer z.bridgesLock.Unlock() 156 157 if br, ok := z.bridges[id]; ok { 158 return br.Info(), nil 159 } 160 return nil, apperr.ErrNotFound 161 } 162 163 // UpdateBridge ... 164 func (z *zigbee2mqtt) UpdateBridge(model *m.Zigbee2mqtt) (err error) { 165 z.bridgesLock.Lock() 166 defer z.bridgesLock.Unlock() 167 168 var bridge *Bridge 169 if bridge, err = z.unsafeGetBridge(model.Id); err == nil { 170 bridge.Stop(context.Background()) 171 delete(z.bridges, model.Id) 172 } else { 173 return 174 } 175 176 bridge = NewBridge(z.mqtt, z.adaptors, model) 177 bridge.Start() 178 z.bridges[model.Id] = bridge 179 180 return 181 } 182 183 // DeleteBridge ... 184 func (z *zigbee2mqtt) DeleteBridge(bridgeId int64) (err error) { 185 z.bridgesLock.Lock() 186 defer z.bridgesLock.Unlock() 187 188 var bridge *Bridge 189 if bridge, err = z.unsafeGetBridge(bridgeId); err == nil { 190 bridge.Stop(context.Background()) 191 delete(z.bridges, bridgeId) 192 } 193 194 return 195 } 196 197 // ResetBridge ... 198 func (z *zigbee2mqtt) ResetBridge(bridgeId int64) (err error) { 199 z.bridgesLock.Lock() 200 defer z.bridgesLock.Unlock() 201 202 var bridge *Bridge 203 if bridge, err = z.unsafeGetBridge(bridgeId); err == nil { 204 bridge.ConfigReset() 205 } 206 return 207 } 208 209 // BridgeDeviceBan ... 210 func (z *zigbee2mqtt) BridgeDeviceBan(bridgeId int64, friendlyName string) (err error) { 211 z.bridgesLock.Lock() 212 defer z.bridgesLock.Unlock() 213 214 var bridge *Bridge 215 if bridge, err = z.unsafeGetBridge(bridgeId); err == nil { 216 bridge.Ban(friendlyName) 217 } 218 return 219 } 220 221 // BridgeDeviceWhitelist ... 222 func (z *zigbee2mqtt) BridgeDeviceWhitelist(bridgeId int64, friendlyName string) (err error) { 223 z.bridgesLock.Lock() 224 defer z.bridgesLock.Unlock() 225 226 var bridge *Bridge 227 if bridge, err = z.unsafeGetBridge(bridgeId); err == nil { 228 bridge.Whitelist(friendlyName) 229 } 230 return 231 } 232 233 // BridgeNetworkmap ... 234 func (z *zigbee2mqtt) BridgeNetworkmap(bridgeId int64) (networkmap string, err error) { 235 z.bridgesLock.Lock() 236 defer z.bridgesLock.Unlock() 237 238 var bridge *Bridge 239 if bridge, err = z.unsafeGetBridge(bridgeId); err == nil { 240 networkmap = bridge.Networkmap() 241 } 242 return 243 } 244 245 // BridgeUpdateNetworkmap ... 246 func (z *zigbee2mqtt) BridgeUpdateNetworkmap(bridgeId int64) (err error) { 247 z.bridgesLock.Lock() 248 defer z.bridgesLock.Unlock() 249 250 var bridge *Bridge 251 if bridge, err = z.unsafeGetBridge(bridgeId); err == nil { 252 bridge.UpdateNetworkmap() 253 } 254 return 255 } 256 257 func (z *zigbee2mqtt) unsafeGetBridge(bridgeId int64) (bridge *Bridge, err error) { 258 var ok bool 259 if bridge, ok = z.bridges[bridgeId]; !ok { 260 err = apperr.ErrNotFound 261 } 262 return 263 } 264 265 // GetTopicByDevice ... 266 func (z *zigbee2mqtt) GetTopicByDevice(model *m.Zigbee2mqttDevice) (topic string, err error) { 267 268 z.bridgesLock.Lock() 269 defer z.bridgesLock.Unlock() 270 271 br, ok := z.bridges[model.Zigbee2mqttId] 272 if !ok { 273 err = apperr.ErrNotFound 274 return 275 } 276 277 topic = br.GetDeviceTopic(model.Id) 278 279 return 280 } 281 282 // DeviceRename ... 283 func (z *zigbee2mqtt) DeviceRename(friendlyName, name string) (err error) { 284 z.bridgesLock.Lock() 285 defer z.bridgesLock.Unlock() 286 287 for _, bridge := range z.bridges { 288 _ = bridge.RenameDevice(friendlyName, name) 289 } 290 291 return 292 } 293 294 // Authenticator ... 295 func (z *zigbee2mqtt) Authenticator(login, password string) (err error) { 296 297 z.bridgesLock.Lock() 298 defer z.bridgesLock.Unlock() 299 300 for _, bridge := range z.bridges { 301 if bridge.model.Login != login { 302 err = apperr.ErrBadLoginOrPassword 303 return 304 } 305 306 if ok := common.CheckPasswordHash(password, bridge.model.EncryptedPassword); ok { 307 err = nil 308 return 309 } 310 } 311 312 err = apperr.ErrBadLoginOrPassword 313 314 return 315 } 316 317 // eventHandler ... 318 func (z *zigbee2mqtt) eventHandler(_ string, message interface{}) { 319 320 var err error 321 switch msg := message.(type) { 322 case events.EventCreatedZigbee2mqttModel: 323 err = z.AddBridge(msg.Bridge) 324 case events.EventUpdatedZigbee2mqttModel: 325 err = z.UpdateBridge(msg.Bridge) 326 case events.EventRemovedZigbee2mqttModel: 327 err = z.DeleteBridge(msg.Id) 328 } 329 330 if err != nil { 331 log.Error(err.Error()) 332 } 333 }