public ZigbeeDevice NewDevice(string friendlyName, string zigbeeId, string modelId)
        {
            ZigbeeDevice device = null;

            Bridge Update(Bridge state)
            {
                device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName));

                if (device == null)
                {
                    device = new ZigbeeDevice.Builder
                    {
                        FriendlyName = friendlyName,
                        IsAvailable  = true,
                        ZigbeeId     = zigbeeId,
                        ModelId      = modelId
                    };
                    state = state.WithDevices(devices => devices.Add(device));
                }

                return(state);
            }

            ImmutableInterlocked.Update(ref _currentState, Update);

            return(device);
        }
Example #2
0
        public void SetDeviceAvailability(string friendlyName, bool isOnline)
        {
            Bridge Update(Bridge state)
            {
                var device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName));

                if (device == null)
                {
                    device = new ZigbeeDevice.Builder {
                        FriendlyName = friendlyName, IsAvailable = isOnline
                    };
                    state = state.WithDevices(devices => devices.Add(device));
                }

                if (device.IsAvailable == isOnline)
                {
                    return(state);
                }

                ZigbeeDevice newDevice = device.WithIsAvailable(isOnline);

                state = state.WithDevices(devices => devices.Replace(device, newDevice));

                return(state);
            }

            UpdateState(Update);
        }
Example #3
0
        public ZigbeeDevice UpdateDevice(string friendlyName, string jsonPayload, out bool forceLastSeen)
        {
            ZigbeeDevice device      = null;
            var          json        = JObject.Parse(jsonPayload);
            var          linkQuality = json["linkquality"]?.Value <ushort>();
            var          battery     = json["battery"]?.Value <decimal>();

            forceLastSeen = !ParseDateTimeOffset(json["last_seen"], out var lastSeen);

            Bridge Update(Bridge state)
            {
                device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName));
                if (device == null)
                {
                    device = new ZigbeeDevice.Builder
                    {
                        FriendlyName = friendlyName,
                        LastSeen     = lastSeen
                    };

                    state = state.WithDevices(devices => devices.Add(device));
                }

                if (lastSeen.HasValue || battery.HasValue)
                {
                    ZigbeeDevice.Builder builder = device;
                    if (lastSeen.HasValue)
                    {
                        builder.LastSeen = lastSeen;
                    }

                    if (battery.HasValue)
                    {
                        builder.BatteryLevel = battery;
                    }

                    ZigbeeDevice newDevice = builder;

                    if (newDevice != device)
                    {
                        state  = state.WithDevices(devices => devices.Replace(device, newDevice));
                        device = newDevice;
                    }
                }

                return(state);
            }

            UpdateState(Update);

            return(device);
        }
        public void UpdateDevices(string payload)
        {
            var json = JArray.Parse(payload);

            Bridge Update(Bridge state)
            {
                foreach (var deviceJson in json)
                {
                    var friendlyName = deviceJson["friendly_name"]?.Value <string>();
                    var zigbeeId     = deviceJson["ieeeAddr"]?.Value <string>();

                    if (string.IsNullOrWhiteSpace(friendlyName))
                    {
                        if (deviceJson["type"]?.Value <string>().Equals("Coordinator", StringComparison.InvariantCultureIgnoreCase) ?? false)
                        {
                            state = state.WithCoordinatorZigbeeId(zigbeeId);
                        }

                        continue;
                    }

                    var          device    = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName) || (d.ZigbeeId?.Equals(zigbeeId) ?? false));
                    ZigbeeDevice newDevice = (device ?? new ZigbeeDevice.Builder {
                        FriendlyName = friendlyName
                    })
                                             .WithZigbeeId(zigbeeId)
                                             .WithType(deviceJson["type"]?.Value <string>())
                                             .WithModel(deviceJson["modelId"]?.Value <string>().Trim().Trim((char)0))
                                             .WithModelId(deviceJson["model"]?.Value <string>().Trim().Trim((char)0))
                                             .WithNetworkAddress(deviceJson["nwkAddr"]?.Value <uint>())
                                             .WithHardwareVersion(deviceJson["hwVersion"]?.Value <long>())
                                             .WithManufacturer(deviceJson["manufName"]?.Value <string>().Trim().Trim((char)0));

                    if (device != newDevice)
                    {
                        state = device == null
                                                        ? state.WithDevices(devices => devices.Add(newDevice))
                                                        : state.WithDevices(devices => devices.Replace(device, newDevice));
                    }
                }

                return(state);
            }

            ImmutableInterlocked.Update(ref _currentState, Update);
        }
        public ZigbeeDevice UpdateDevice(string friendlyName, string jsonPayload)
        {
            ZigbeeDevice device      = null;
            var          json        = JObject.Parse(jsonPayload);
            var          linkQuality = json["linkquality"]?.Value <ushort>();
            var          lastSeen    = json["last_seen"]?.Value <DateTime>();

            Bridge Update(Bridge state)
            {
                device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName));
                if (device == null)
                {
                    device = new ZigbeeDevice.Builder
                    {
                        FriendlyName = friendlyName,
                        LastSeen     = lastSeen
                    };

                    state = state.WithDevices(devices => devices.Add(device));
                }

                if (lastSeen.HasValue)
                {
                    var newDevice = device.WithLastSeen(lastSeen);

                    if (newDevice != device)
                    {
                        state  = state.WithDevices(devices => devices.Replace(device, newDevice));
                        device = newDevice;
                    }
                }

                return(state);
            }

            ImmutableInterlocked.Update(ref _currentState, Update);

            return(device);
        }
Example #6
0
        public void UpdateRenamedDevice(string from, string to)
        {
            Bridge Update(Bridge state)
            {
                var device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(from));

                if (device == null)
                {
                    return(state);
                }

                ZigbeeDevice newDevice = device.WithFriendlyName(to);

                if (newDevice != device)
                {
                    state = state.WithDevices(devices => devices.Replace(device, newDevice));
                }

                return(state);
            }

            UpdateState(Update);
        }
        public IReadOnlyCollection <IReadOnlyCollection <ZigbeeDevice> > GetRoutesToCoordinator(ZigbeeDevice forDevice)
        {
            var state = _currentState;

            var processedDevices = new List <ZigbeeDevice>(state.Devices.Length - 1);

            IEnumerable <IReadOnlyCollection <ZigbeeDevice> > GetRoutes(ZigbeeDevice d)
            {
                if (processedDevices.Contains(d))
                {
                    yield break;                     // already processed routed through this device
                }
            }

            return(GetRoutes(forDevice).ToImmutableArray());
        }
        public HomeAssistantEntity SetDeviceEntity(
            string zigbeeId,
            string entityClass,
            string component,
            string configPayload,
            Func <string, string> friendlyNameFromTopicDelegate)
        {
            HomeAssistantEntity entity = null;

            var json = JObject.Parse(configPayload);

            var entityName = json["name"]?.Value <string>();
            var entityId   = json["unique_id"]?.Value <string>();
            var deviceName = json["device"]["name"]?.Value <string>();
            var deviceIds  = json["device"]["identifiers"]?.FirstOrDefault()?.Value <string>();

            Bridge Update(Bridge state)
            {
                var device = state.Devices.FirstOrDefault(d => d.ZigbeeId != null && d.ZigbeeId.Equals(zigbeeId));

                if (device == null)
                {
                    // no device with this zigbeeId is known, try to find device from payload
                    var topic = json["state_topic"].Value <string>()
                                ?? json["json_attributes_topic"].Value <string>()
                                ?? json["availability_topic"].Value <string>();

                    if (topic == null)
                    {
                        _logger.LogWarning($"Unable to find a source topic for entity {zigbeeId}-{entityClass}-{component}.");
                        return(state);                        // there's nothing we can do here
                    }

                    var friendlyName = friendlyNameFromTopicDelegate(topic);

                    if (friendlyName == null)
                    {
                        _logger.LogWarning($"Unable to find friendly name from topic {topic} in entity {zigbeeId}-{entityClass}-{component}.");
                        return(state);                        // there's nothing we can do here
                    }

                    device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName));
                    if (device == null)
                    {
                        device = new ZigbeeDevice.Builder {
                            FriendlyName = friendlyName, UniqueId = zigbeeId, ZigbeeId = zigbeeId
                        };
                        state = state.WithDevices(devices => devices.Add(device));
                    }
                }

                if (device.ZigbeeId != zigbeeId)
                {
                    ZigbeeDevice newDevice = device.WithUniqueId(zigbeeId);

                    if (newDevice != device)
                    {
                        state  = state.WithDevices(devices => devices.Replace(device, newDevice));
                        device = newDevice;
                    }
                }

                entity = device.Entities.FirstOrDefault(e => e.Component.Equals(component));
                if (entity == null)
                {
                    entity = new HomeAssistantEntity.Builder
                    {
                        EntityId    = entityId,
                        Component   = component,
                        Name        = entityName,
                        DeviceClass = entityClass
                    };
                    ZigbeeDevice newDevice = device.WithEntities(entities => entities.Add(entity));

                    if (newDevice != device)
                    {
                        state  = state.WithDevices(devices => devices.Replace(device, newDevice));
                        device = newDevice;
                    }
                }

                if (deviceName != null || deviceIds != null)
                {
                    ZigbeeDevice newDevice = device
                                             .WithName(deviceName)
                                             .WithUniqueId(deviceIds);

                    if (newDevice != device)
                    {
                        state  = state.WithDevices(devices => devices.Replace(device, newDevice));
                        device = newDevice;
                    }
                }

                return(state);
            }

            ImmutableInterlocked.Update(ref _currentState, Update);

            return(entity);
        }
Example #9
0
        public void UpdateDevices(string payload)
        {
            var json = JToken.Parse(payload);

            if (json.Type == JTokenType.Object && json["type"]?.Value <string>() == "devices")
            {
                json = json["message"];
            }

            if (json.Type != JTokenType.Array)
            {
                _logger.LogWarning($"Invalid/unknown devices payload received. root element type is {json.Root.Type}: {payload.Substring(0, Math.Min(40, payload.Length))}... -- will be ignored.");
                return;
            }

            Bridge Update(Bridge state)
            {
                foreach (var deviceJson in json)
                {
                    var friendlyName = deviceJson["friendly_name"]?.Value <string>();
                    var zigbeeId     = deviceJson["ieeeAddr"]?.Value <string>();

                    var deviceType = deviceJson["type"]?.Value <string>();

                    if (string.IsNullOrWhiteSpace(friendlyName))
                    {
                        if (deviceType?.Equals("Coordinator", StringComparison.InvariantCultureIgnoreCase) ?? false)
                        {
                            state        = state.WithCoordinatorZigbeeId(zigbeeId);
                            friendlyName = "Coordinator";
                        }
                        else
                        {
                            _logger.LogWarning($"Unable to understand device with json {deviceJson} -- will be ignored.");
                            continue;                             // unable to qualify this device
                        }
                    }

                    var device          = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName) || (d.ZigbeeId?.Equals(zigbeeId) ?? false));
                    var networkAddress  = (deviceJson["nwkAddr"] ?? deviceJson["networkAddress"])?.Value <uint>();
                    var model           = (deviceJson["modelId"] ?? deviceJson["modelID"])?.Value <string>().Trim().Trim((char)0);
                    var modelId         = deviceJson["model"]?.Value <string>().Trim().Trim((char)0);
                    var manufacturer    = (deviceJson["manufName"] ?? deviceJson["manufacturerName"])?.Value <string>().Trim().Trim((char)0);
                    var hardwareVersion = (deviceJson["hwVersion"] ?? deviceJson["hardwareVersion"])?.Value <long>();

                    ZigbeeDevice newDevice = (device ?? new ZigbeeDevice.Builder {
                        FriendlyName = friendlyName
                    })
                                             .WithZigbeeId(zigbeeId)
                                             .WithType(deviceType)
                                             .WithNetworkAddress(networkAddress)
                                             .WithModel(model)
                                             .WithModelId(modelId)
                                             .WithManufacturer(manufacturer)
                                             .WithHardwareVersion(hardwareVersion);

                    if (ParseDateTimeOffset(deviceJson["lastSeen"], out var lastSeen))
                    {
                        newDevice = newDevice.WithLastSeen(lastSeen);
                    }

                    if (device != newDevice)
                    {
                        state = device == null
                                                        ? state.WithDevices(devices => devices.Add(newDevice))
                                                        : state.WithDevices(devices => devices.Replace(device, newDevice));
                    }
                }

                return(state);
            }

            UpdateState(Update);
        }
Example #10
0
        public ZigbeeDevice UpdateDevice(string friendlyName, string jsonPayload, out bool forceLastSeen)
        {
            ZigbeeDevice device = null;

            if (!TryParseJson(jsonPayload, out var json))
            {
                forceLastSeen = false;
                return(null);
            }

            var linkQuality = json["linkquality"]?.Value <ushort>();

            forceLastSeen = !ParseDateTimeOffset(json["last_seen"], out var lastSeen);

            Bridge Update(Bridge state)
            {
                device = state.Devices.FirstOrDefault(d => d.FriendlyName.Equals(friendlyName));
                if (device == null)
                {
                    device = new ZigbeeDevice.Builder
                    {
                        FriendlyName = friendlyName,
                        LastSeen     = lastSeen
                    };

                    state = state.WithDevices(devices => devices.Add(device));
                }

                var battery         = json["battery"]?.Value <decimal>();
                var updateAvailable = json["update_available"]?.Value <bool?>();

                if (!lastSeen.HasValue && !battery.HasValue && !updateAvailable.HasValue)
                {
                    return(state);
                }

                ZigbeeDevice.Builder builder = device;
                if (lastSeen.HasValue)
                {
                    builder.LastSeen = lastSeen;
                }

                if (battery.HasValue)
                {
                    builder.BatteryLevel = battery;
                }

                if (updateAvailable.HasValue)
                {
                    builder.IsOtaAvailable = updateAvailable;
                }

                ZigbeeDevice newDevice = builder;

                if (newDevice == device)
                {
                    return(state);
                }

                state  = state.WithDevices(devices => devices.Replace(device, newDevice));
                device = newDevice;

                return(state);
            }

            UpdateState(Update);

            return(device);
        }