mirror of
https://bitbucket.org/myhomie/mycorerepository.git
synced 2025-12-06 17:51:20 +00:00
352 lines
16 KiB
C#
352 lines
16 KiB
C#
using MQTTnet;
|
|
using MQTTnet.Client;
|
|
using MQTTnet.Client.Connecting;
|
|
using MQTTnet.Client.Disconnecting;
|
|
using MQTTnet.Client.Options;
|
|
using MyCore.Interfaces.DTO;
|
|
using MyCore.Interfaces.Models;
|
|
using MyCore.Interfaces.Models.Providers.Zigbee.Zigbee2Mqtt;
|
|
using MyCore.Service.Services;
|
|
using MyCore.Services;
|
|
using MyCore.Services.Devices;
|
|
using MyCore.Services.MyControlPanel;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Mqtt.Client.AspNetCore.Services
|
|
{
|
|
public class MqttClientService : IMqttClientService
|
|
{
|
|
private static IMqttClient mqttClient;
|
|
private IMqttClientOptions options;
|
|
public static List<Zigbee2MqttDeviceConfig> devices = new List<Zigbee2MqttDeviceConfig>();
|
|
public static List<Zigbee2MqttDevice> devicesNew = new List<Zigbee2MqttDevice>();
|
|
public static List<Zigbee2MqttGroup> groups = new List<Zigbee2MqttGroup>();
|
|
public static string homeId;
|
|
private DeviceDatabaseService _deviceDatabaseService;
|
|
private GroupDatabaseService _groupDatabaseService;
|
|
private ProviderDatabaseService _providerDatabaseService;
|
|
private RoomDatabaseService _roomDatabaseService;
|
|
private AutomationDatabaseService _automationDatabaseService;
|
|
private ActionService _actionService;
|
|
private HomeDatabaseService _homeDatabaseService;
|
|
private AlarmDatabaseService _alarmDatabaseService;
|
|
private EventDatabaseService _eventDatabaseService;
|
|
|
|
public static string lastTopic;
|
|
public static long lastTimeTopic;
|
|
|
|
public MqttClientService(IMqttClientOptions options, HomeDatabaseService homeDatabaseService, DeviceDatabaseService deviceDatabaseService, GroupDatabaseService groupDatabaseService, ProviderDatabaseService providerDatabaseService, RoomDatabaseService roomDatabaseService, ActionService actionService, AutomationDatabaseService automationDatabaseService, AlarmDatabaseService alarmDatabaseService, EventDatabaseService eventDatabaseService)
|
|
{
|
|
this._homeDatabaseService = homeDatabaseService;
|
|
this._deviceDatabaseService = deviceDatabaseService;
|
|
this._groupDatabaseService = groupDatabaseService;
|
|
this._providerDatabaseService = providerDatabaseService;
|
|
this._roomDatabaseService = roomDatabaseService;
|
|
this._automationDatabaseService = automationDatabaseService;
|
|
this._alarmDatabaseService = alarmDatabaseService;
|
|
this._eventDatabaseService = eventDatabaseService;
|
|
this._actionService = actionService;
|
|
|
|
Home home = this._homeDatabaseService.GetAll().ToList().Where(h => h.IsDefault).FirstOrDefault();
|
|
if (home != null)
|
|
homeId = home.Id;
|
|
|
|
System.Console.WriteLine($"Home Id in MQTT client service : {homeId}");
|
|
|
|
var server = "localhost";
|
|
var clientId = "ApiService";
|
|
#if DEBUG
|
|
server = "192.168.31.140";
|
|
clientId = "ApiServiceTest";
|
|
#endif
|
|
//this.options = options;
|
|
this.options = new MqttClientOptionsBuilder()
|
|
.WithClientId(clientId)
|
|
.WithTcpServer(server)
|
|
.WithCredentials("mqtt", "mqtt")
|
|
.WithCleanSession()
|
|
.Build();
|
|
mqttClient = new MqttFactory().CreateMqttClient();
|
|
ConfigureMqttClient();
|
|
}
|
|
|
|
private void ConfigureMqttClient()
|
|
{
|
|
mqttClient.ConnectedHandler = this;
|
|
mqttClient.DisconnectedHandler = this;
|
|
mqttClient.ApplicationMessageReceivedHandler = this;
|
|
}
|
|
|
|
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e)
|
|
{
|
|
var payload = "";
|
|
if (e.ApplicationMessage.Payload != null)
|
|
{
|
|
payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
|
|
}
|
|
|
|
var topic = e.ApplicationMessage.Topic;
|
|
|
|
var currentTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
|
|
// For check if not doubled message (example : motion double true value)
|
|
var test = currentTime - lastTimeTopic;
|
|
|
|
var isWakeUpMessage = false;
|
|
// if wakeup => Not drop wakeup message
|
|
try
|
|
{
|
|
var deserialized = JsonConvert.DeserializeObject<Dictionary<string, object>>(payload);
|
|
|
|
if (deserialized != null) {
|
|
isWakeUpMessage = (string)deserialized["action"] == "wakeup";
|
|
}
|
|
} catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
|
|
var configMessage = topic == "zigbee2mqtt/bridge/event";
|
|
|
|
// Less than one second between two messages from a same device
|
|
if (!(lastTopic == topic && test <= 500) || configMessage)
|
|
{
|
|
if (_actionService != null && homeId != null)
|
|
{
|
|
ActionService.HandleActionFromMQTTAsync(topic, payload, _deviceDatabaseService, _groupDatabaseService, _providerDatabaseService, _roomDatabaseService, _automationDatabaseService, _alarmDatabaseService, _eventDatabaseService, homeId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO Check if not a valuable message (example state true to false => correct message..)
|
|
System.Console.WriteLine($"Drop message - spam from {topic}");
|
|
}
|
|
|
|
UpdateZigbee2MqttConfigOrStateAsync(topic, payload, homeId, _deviceDatabaseService, _groupDatabaseService, _providerDatabaseService, _roomDatabaseService);
|
|
|
|
switch (topic)
|
|
{
|
|
case "zigbee2mqtt/bridge/config/devices":
|
|
try
|
|
{
|
|
var devicesConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttDeviceConfig>>(payload);
|
|
devices = devicesConvert;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
|
|
}
|
|
break;
|
|
case "zigbee2mqtt/bridge/groups":
|
|
try
|
|
{
|
|
var groupsConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttGroup>>(payload);
|
|
groups = groupsConvert;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving groups ! Exception: {ex}");
|
|
}
|
|
break;
|
|
case "zigbee2mqtt/bridge/devices":
|
|
try
|
|
{
|
|
var devicesConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(payload);
|
|
devicesNew = devicesConvert;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!isWakeUpMessage) {
|
|
lastTimeTopic = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
lastTopic = topic;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs)
|
|
{
|
|
System.Console.WriteLine("connected");
|
|
await mqttClient.SubscribeAsync("#");
|
|
await PublishMessage("zigbee2mqtt/bridge/config/devices/get", "");
|
|
}
|
|
|
|
public async Task HandleDisconnectedAsync(MqttClientDisconnectedEventArgs eventArgs)
|
|
{
|
|
if (!mqttClient.IsConnected)
|
|
{
|
|
await mqttClient.ReconnectAsync();
|
|
}
|
|
}
|
|
|
|
public async Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
await mqttClient.ConnectAsync(options);
|
|
if (!mqttClient.IsConnected)
|
|
{
|
|
await mqttClient.ReconnectAsync();
|
|
}
|
|
}
|
|
|
|
public async Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
if(cancellationToken.IsCancellationRequested)
|
|
{
|
|
var disconnectOption = new MqttClientDisconnectOptions
|
|
{
|
|
ReasonCode = MqttClientDisconnectReason.NormalDisconnection,
|
|
ReasonString = "NormalDiconnection"
|
|
};
|
|
await mqttClient.DisconnectAsync(disconnectOption, cancellationToken);
|
|
}
|
|
await mqttClient.DisconnectAsync();
|
|
}
|
|
|
|
public static async Task PublishMessage(string topic, string message, bool retain = false)
|
|
{
|
|
var mqttMessage = new MqttApplicationMessageBuilder()
|
|
.WithTopic(topic)
|
|
.WithPayload(message)
|
|
.WithExactlyOnceQoS()
|
|
.WithRetainFlag(retain)
|
|
.Build();
|
|
|
|
if (mqttClient.IsConnected)
|
|
await mqttClient.PublishAsync(mqttMessage);
|
|
}
|
|
|
|
/*public static void SetServices(DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, ActionService _ActionService, AutomationDatabaseService _AutomationDatabaseService, string HomeId)
|
|
{
|
|
_deviceDatabaseService = _DeviceDatabaseService;
|
|
_groupDatabaseService = _GroupDatabaseService;
|
|
_providerDatabaseService = _ProviderDatabaseService;
|
|
_roomDatabaseService = _RoomDatabaseService;
|
|
_automationDatabaseService = _AutomationDatabaseService;
|
|
_actionService = _ActionService;
|
|
homeId = HomeId;
|
|
}*/
|
|
|
|
public static async Task UpdateZigbee2MqttConfigOrStateAsync(string topic, string message, string homeId, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService)
|
|
{
|
|
// update zigbee2mqqtt config
|
|
switch (topic)
|
|
{
|
|
case "zigbee2mqtt/bridge/config/devices":
|
|
try
|
|
{
|
|
var devices = JsonConvert.DeserializeObject<List<Zigbee2MqttDeviceConfig>>(message);
|
|
var zigbee2mqttProvider = _ProviderDatabaseService.GetByType(ProviderType.zigbee2mqtt);
|
|
|
|
if (zigbee2mqttProvider != null)
|
|
{
|
|
// Retrieve existing devices
|
|
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(zigbee2mqttProvider.Id);
|
|
var existingDevicesAddresses = existingDevices.Select(ed => ed.ServiceIdentification);
|
|
|
|
// Filter devices and check if something new
|
|
var filteredDevices = devices.Where(d => !existingDevicesAddresses.Contains(d.ieeeAddr)).ToList();
|
|
// Add new devices
|
|
Dictionary<string, List<DeviceDetailDTO>> createdDevices = await DeviceService.CreateFromZigbeeAsync(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, filteredDevices, zigbee2mqttProvider);
|
|
}
|
|
|
|
System.Console.WriteLine($"Devices updated for home {homeId}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
|
|
}
|
|
break;
|
|
case "zigbee2mqtt/bridge/devices":
|
|
try
|
|
{
|
|
var devices = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(message);
|
|
var zigbee2mqttProvider = _ProviderDatabaseService.GetByType(ProviderType.zigbee2mqtt);
|
|
|
|
if (zigbee2mqttProvider != null)
|
|
{
|
|
// Retrieve existing devices
|
|
/*List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(zigbee2mqttProvider.Id);
|
|
var existingDevicesAddresses = existingDevices.Select(ed => ed.ServiceIdentification);*/
|
|
|
|
System.Console.WriteLine($"Nbr of devices : {devices.Count}");
|
|
|
|
// Update supported operation
|
|
Dictionary<string, List<DeviceDetailDTO>> createdDevices = await DeviceService.UpdateFromZigbeeAsync(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, devices, zigbee2mqttProvider);
|
|
}
|
|
|
|
System.Console.WriteLine($"Devices updated for home {homeId} - more information");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
|
|
}
|
|
break;
|
|
case "zigbee2mqtt/bridge/groups":
|
|
try
|
|
{
|
|
var groupsConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttGroup>>(message);
|
|
|
|
var zigbee2mqttProvider = _ProviderDatabaseService.GetByType(ProviderType.zigbee2mqtt);
|
|
|
|
if (zigbee2mqttProvider != null)
|
|
{
|
|
var groups = _GroupDatabaseService.GetByType(homeId, "zigbee2mqtt");
|
|
|
|
GroupService.CompareGroupsFromZigbee2Mqtt(homeId, groups, groupsConvert, _DeviceDatabaseService, _GroupDatabaseService);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving groups ! Exception: {ex}");
|
|
}
|
|
break;
|
|
case "zigbee2mqtt/bridge/event":
|
|
try
|
|
{
|
|
var eventConvert = JsonConvert.DeserializeObject<Zigbee2MqttEvent>(message);
|
|
|
|
if (eventConvert.data?.ieee_address != null)
|
|
{
|
|
var zigbeeDevice = _DeviceDatabaseService.GetByServiceIdentification(eventConvert.data.ieee_address);
|
|
|
|
if (zigbeeDevice != null && eventConvert.type == "device_announce") // Check if we can not hardcode that..
|
|
{
|
|
var status = new List<AutomationState>();
|
|
var state = new AutomationState();
|
|
state.Name = "state";
|
|
state.Value = "on";
|
|
status.Add(state);
|
|
|
|
var buildRequest = new Dictionary<string, object>();
|
|
buildRequest.Add(state.Name, state.Value);
|
|
|
|
// Update device state !
|
|
zigbeeDevice.LastState = JsonConvert.SerializeObject(buildRequest);
|
|
zigbeeDevice.LastStateDate = DateTime.Now;
|
|
_DeviceDatabaseService.Update(zigbeeDevice);
|
|
|
|
// Check if all group has the same state // Not needed as we test the first device of a group
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving event ! Exception: {ex}");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|