mirror of
https://bitbucket.org/myhomie/mycorerepository.git
synced 2025-12-06 01:31:19 +00:00
482 lines
31 KiB
C#
482 lines
31 KiB
C#
using Mqtt.Client.AspNetCore.Services;
|
|
using MyCore.Interfaces.DTO;
|
|
using MyCore.Interfaces.Models;
|
|
using MyCore.Interfaces.Models.Providers.Zigbee.Aqara;
|
|
using MyCore.Service.Services;
|
|
using MyCore.Services.MyControlPanel;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using static Mqtt.Client.AspNetCore.Services.MqttClientMerossService;
|
|
|
|
namespace MyCore.Services.Devices
|
|
{
|
|
public class ActionService
|
|
{
|
|
public static bool isOpen = false;
|
|
public static long lastActionTime;
|
|
//private static dynamic deserializedReceivedMessage;
|
|
//private static dynamic triggerStateName;
|
|
//private static dynamic triggerStateValueCheck;
|
|
|
|
public static void HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, AutomationDatabaseService _AutomationDatabaseService, string userId)
|
|
{
|
|
var actionTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
|
|
var providers = _ProviderDatabaseService.GetAll(userId);
|
|
string[] topicSplit = topic.Split('/');
|
|
|
|
var providerFromTopic = topicSplit[0];
|
|
|
|
// TODO Sortir automation d'un type specific.. et créer un objet ?
|
|
|
|
System.Console.WriteLine($"Received message {message}");
|
|
switch (providerFromTopic) {
|
|
case "zigbee2mqtt":
|
|
UpdateZigbee2MqttConfigAsync(topic, message, userId, _DeviceDatabaseService, _GroupDatabaseService, _ProviderDatabaseService, _LocationDatabaseService);
|
|
|
|
var provider = _ProviderDatabaseService.GetByType(topicSplit[0]).Id;
|
|
var automations = _AutomationDatabaseService.GetByProvider(provider);
|
|
|
|
var serviceName = topicSplit[1];
|
|
var zigbeeDevice = _DeviceDatabaseService.GetByName(serviceName).FirstOrDefault();
|
|
|
|
if (zigbeeDevice != null) {
|
|
try
|
|
{
|
|
|
|
/*
|
|
// Todo Deserialize by type
|
|
switch (zigbeeDevice.Type)
|
|
{
|
|
case DeviceType.Switch:
|
|
deserializedReceivedMessage = JsonConvert.DeserializeObject<AqaraCube>(message);
|
|
zigbeeDevice.LastState = message;
|
|
break;
|
|
case DeviceType.Light:
|
|
deserializedReceivedMessage = JsonConvert.DeserializeObject<LightBulb>(message);
|
|
zigbeeDevice.LastState = message;
|
|
break;
|
|
case DeviceType.Motion:
|
|
deserializedReceivedMessage = JsonConvert.DeserializeObject<AqaraMotion>(message);
|
|
zigbeeDevice.LastState = message;
|
|
break;
|
|
case DeviceType.Plug:
|
|
zigbeeDevice.LastState = message;
|
|
break;
|
|
default:
|
|
break;
|
|
}*/
|
|
|
|
// if is not a set => check automation
|
|
if (topicSplit.Length <= 2)
|
|
{
|
|
foreach (var automation in automations)
|
|
{
|
|
|
|
// todo check if not null and if more than one element
|
|
if (zigbeeDevice != null && automation.Triggers.Any(t => t.DeviceId == zigbeeDevice.Id))
|
|
{
|
|
System.Console.WriteLine($"Open automation {automation.Name}");
|
|
var automationTrigger = automation.Triggers.Where(t => t.DeviceId == zigbeeDevice.Id).FirstOrDefault();
|
|
|
|
List<Expose> exposes = GetDeviceExposes(zigbeeDevice);
|
|
|
|
var triggerStateValueCheck = (object) null;
|
|
|
|
// Try to get automationTrigger.StateName of zigbee device
|
|
var expose = exposes.Where(e => e.name == automationTrigger.StateName).FirstOrDefault();
|
|
bool validTrigger = expose != null; // No expose found.. => the device has not the correct state => not correct automation
|
|
|
|
//System.Type typeToCheck = GetStateType(expose);
|
|
|
|
try
|
|
{
|
|
// Try to get specific field from message
|
|
var dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(message);
|
|
triggerStateValueCheck = dic[automationTrigger.StateName]; // if action slide => get slide
|
|
}
|
|
catch (Exception ex) {
|
|
validTrigger = false;
|
|
}
|
|
|
|
|
|
if (validTrigger && automationTrigger.StateValue.ToLower() == triggerStateValueCheck.ToString().ToLower())
|
|
{
|
|
// Correct trigger !
|
|
|
|
// Todo check condition
|
|
if (automation.Conditions.Count <= 0)
|
|
{
|
|
System.Console.WriteLine("None conditions");
|
|
foreach (var action in automation.Actions)
|
|
{
|
|
System.Console.WriteLine($"Check Action ! {action.StateName} {action.StateValue}");
|
|
var stateName = action.StateName;
|
|
var stateValue = action.StateValue;
|
|
|
|
var actionName = "";
|
|
Device actionDeviceToTest = new Device();
|
|
|
|
switch (action.Type) {
|
|
case Interfaces.Models.Type.DEVICE:
|
|
var zigbeeDeviceAction = _DeviceDatabaseService.GetById(action.DeviceId);
|
|
var providerActionTest = _ProviderDatabaseService.GetById(userId, action.ProviderId);
|
|
|
|
actionName = zigbeeDeviceAction.Name;
|
|
actionDeviceToTest = zigbeeDeviceAction;
|
|
System.Console.WriteLine($"We get a zigbeeDeviceAction ! Name={zigbeeDeviceAction.Name} Type={zigbeeDeviceAction.Type}");
|
|
System.Console.WriteLine($"Check action provider type ! Type={providerActionTest.Type} Name={providerActionTest.Name}");
|
|
break;
|
|
case Interfaces.Models.Type.GROUP:
|
|
var zigbeeGroupAction = _GroupDatabaseService.GetById(action.GroupId);
|
|
actionName = zigbeeGroupAction.Name;
|
|
|
|
System.Console.WriteLine($"We get a zigbeeGroupAction ! Name={zigbeeGroupAction.Name} Type={zigbeeGroupAction.Type}");
|
|
System.Console.WriteLine($"Check action zigbeeGroupAction type ! Type={zigbeeGroupAction.Type}");
|
|
|
|
// Check state of first device of a group
|
|
actionDeviceToTest = _DeviceDatabaseService.GetByGroup(zigbeeGroupAction.Id).FirstOrDefault(); // TODO : Send error if no device found !
|
|
break;
|
|
case Interfaces.Models.Type.MQTT: // Correct way ?
|
|
// TODO
|
|
//requestType = Interfaces.Models.Type.MQTT;
|
|
break;
|
|
case Interfaces.Models.Type.HTTP: // Correct way ?
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
var providerAction = _ProviderDatabaseService.GetById(userId, action.ProviderId);
|
|
|
|
// Check if device exist
|
|
if (actionDeviceToTest != null)
|
|
{
|
|
switch (providerAction.Type)
|
|
{
|
|
case "zigbee2mqtt":
|
|
//Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { };
|
|
var request = "";
|
|
|
|
// If the state is already good, do not send the request. (in order to not spam mqtt broker)
|
|
bool alreadyInAskedState = false;
|
|
|
|
System.Console.WriteLine($"zigbee2mqtt type !");
|
|
|
|
var actionDeviceExpose = GetDeviceExposes(actionDeviceToTest);
|
|
bool validAction = false;
|
|
|
|
if (actionDeviceToTest.Type == DeviceType.Light || actionDeviceToTest.Type == DeviceType.Switch)
|
|
{
|
|
var typeToTest = actionDeviceToTest.Type == DeviceType.Light ? "light" : "switch";
|
|
var exposeToTest = actionDeviceExpose.Where(e => e.type == typeToTest).FirstOrDefault();
|
|
validAction = exposeToTest != null;
|
|
}
|
|
else {
|
|
// Retrieve exposes for actionDevice
|
|
var exposeToTest = actionDeviceExpose.Where(e => e.name == action.StateName).FirstOrDefault();
|
|
validAction = exposeToTest != null;
|
|
}
|
|
|
|
if (validAction)
|
|
{
|
|
|
|
var dic = new Dictionary<string, object>();
|
|
if (actionDeviceToTest.LastState != null) {
|
|
dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(actionDeviceToTest.LastState);
|
|
}
|
|
|
|
// TODO: Check if switch correct and if we can toggle => Same for Plug etc (depend on request)
|
|
// TODO: Check if device has brightness possibility..
|
|
bool isBrightness = false;
|
|
|
|
if (actionDeviceToTest.Type == DeviceType.Light || actionDeviceToTest.Type == DeviceType.Switch)
|
|
{
|
|
|
|
var requestBefore = new Dictionary<string, object>();
|
|
requestBefore.Add(action.StateName, action.StateValue);
|
|
|
|
request = JsonConvert.SerializeObject(requestBefore);
|
|
|
|
if (dic.Count > 0) {
|
|
if (dic["state"].ToString().ToLower() == stateValue.ToLower())
|
|
{
|
|
alreadyInAskedState = true;
|
|
}
|
|
}
|
|
|
|
/*if (stateValue == DeviceAction.toggle.ToString())
|
|
{
|
|
System.Console.WriteLine($"Toggle action");
|
|
// TODO => Check exposes device etc
|
|
switch (dic["state"].ToLower())
|
|
{
|
|
case "on":
|
|
actionRequest = "off";
|
|
|
|
zigbee2MqttRequest.brightness = 0;
|
|
break;
|
|
case "off":
|
|
case null:
|
|
default:
|
|
actionRequest = "on";
|
|
zigbee2MqttRequest.brightness = 255;
|
|
break;
|
|
}
|
|
}
|
|
else if (stateValue.ToLower() == DeviceAction.on.ToString().ToLower())
|
|
{
|
|
// retrieve device state to check if already in asked state
|
|
if (dic["state"].ToLower() == stateValue.ToLower())
|
|
alreadyInAskedState = true;
|
|
else
|
|
{
|
|
actionRequest = "on";
|
|
zigbee2MqttRequest.brightness = 255;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// DeviceAction.off.ToString() => Need to ad validation ?
|
|
|
|
// retrieve device state to check if already in asked state
|
|
if (dic["state"].ToLower() == stateValue.ToLower())
|
|
alreadyInAskedState = true;
|
|
else
|
|
{
|
|
actionRequest = "off";
|
|
zigbee2MqttRequest.brightness = 0;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
if (!alreadyInAskedState)
|
|
{
|
|
/*System.Console.WriteLine($"Before retrieving type etc {zigbee2MqttRequest.state}");
|
|
|
|
System.Type type2 = zigbee2MqttRequest.GetType();
|
|
PropertyInfo property2 = type2.GetProperty(stateName);
|
|
property2.SetValue(zigbee2MqttRequest, actionRequest, null);
|
|
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);*/
|
|
|
|
var requestToSend = $"Send request ! zigbee2mqtt/{actionName}/set/{request}";
|
|
System.Console.WriteLine($"Send request ! zigbee2mqtt/{actionName}/set/{request}");
|
|
|
|
MqttClientService.PublishMessage("zigbee2mqtt/" + actionName + "/set", request);
|
|
}
|
|
}
|
|
else {
|
|
// No expose found.. => the device has not the correct state => not correct automation
|
|
System.Console.WriteLine($"Invalid action - the request was not sent");
|
|
}
|
|
break;
|
|
case "meross":
|
|
System.Console.WriteLine($"meross type !");
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
System.Console.WriteLine($"Device or group found in action incorrect");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
zigbeeDevice.LastStateDate = DateTime.Now;
|
|
zigbeeDevice.LastState = message;
|
|
_DeviceDatabaseService.Update(zigbeeDevice);
|
|
}
|
|
else
|
|
{
|
|
// do nothing is a set
|
|
}
|
|
}
|
|
catch (Exception ex) { }
|
|
}
|
|
// switch case according to device type (topic !)
|
|
if (topicSplit[1].Contains("MagicCube0"))
|
|
{
|
|
var test = JsonConvert.DeserializeObject<AqaraCube>(message);
|
|
/*if (test.Action == "shake")
|
|
{
|
|
if (YeelightService.devices.Count <= 0) {
|
|
await YeelightService.GetDevices();
|
|
}
|
|
var labLamp = YeelightService.devices.Where(d => d.Hostname == "192.168.31.74").FirstOrDefault();
|
|
if (labLamp != null) {
|
|
Task.Run(async () => { await YeelightService.Toggle(labLamp); });
|
|
}
|
|
}*/
|
|
/* if (test.action == "shake")
|
|
{
|
|
// TODO Check state
|
|
|
|
Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { state = "OFF", brightness = 0 };
|
|
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);
|
|
|
|
MqttClientService.PublishMessage("zigbee2mqtt/GU10Bureau/set", request);
|
|
}*/
|
|
if (test.action == "tap")
|
|
{
|
|
var merossProvider = providers.Where(p => p.Type == "meross").FirstOrDefault();
|
|
var merossDevices = _DeviceDatabaseService.GetByProviderId(merossProvider.Id);
|
|
|
|
var multiprise = merossDevices.Where(md => md.Name == "Multiprise bureau").FirstOrDefault();
|
|
//var prise = merossDevices.Where(md => md.Name == "Imprimante 3D").FirstOrDefault();
|
|
|
|
if (multiprise != null)
|
|
{
|
|
//As multisocket channel 0 is all the sockets, skip 0
|
|
var tests = actionTime - lastActionTime;
|
|
if (tests >= 1000) {
|
|
isOpen = !isOpen;
|
|
if (isOpen)
|
|
{
|
|
/*foreach (var channel in multiprise.channels)
|
|
{
|
|
if (i != 0)
|
|
MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, i);
|
|
i++;
|
|
}*/
|
|
MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 1);
|
|
/*MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 2);
|
|
MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 3);*/
|
|
//MqttClientMerossService.ExecuteCommand(prise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 0);
|
|
}
|
|
else
|
|
{
|
|
MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 1);
|
|
/*MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 2);
|
|
MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 3);*/
|
|
//MqttClientMerossService.ExecuteCommand(prise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 0);
|
|
}
|
|
}
|
|
|
|
lastActionTime = actionTime;
|
|
|
|
}
|
|
/*if (lightStateIkeaBulb == LightState.Undefined || lightStateIkeaBulb == LightState.Off)
|
|
PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"ON\"}");
|
|
else
|
|
PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"OFF\"}");*/
|
|
}
|
|
//await MqttClientOnlineService.PublishMessage("Notification", "Hey magic cube 0 !");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static List<Expose> GetDeviceExposes(Device device)
|
|
{
|
|
List<Expose> exposes = new List<Expose>();
|
|
// Get Exposes for the zigbee device
|
|
foreach (var supportedOperation in device.SupportedOperations)
|
|
{
|
|
exposes.Add(JsonConvert.DeserializeObject<Expose>(supportedOperation));
|
|
}
|
|
return exposes;
|
|
}
|
|
|
|
private static System.Type GetStateType(Expose expose)
|
|
{
|
|
switch (expose.type)
|
|
{
|
|
// e.g.: occupancy
|
|
case "binary":
|
|
if (expose.value_toggle == null)
|
|
{
|
|
// value are boolean
|
|
return true.GetType();
|
|
}
|
|
else
|
|
{
|
|
// value are string
|
|
return "".GetType();
|
|
}
|
|
case "numeric":
|
|
return new long().GetType();
|
|
case "enum":
|
|
return expose.values.GetType();
|
|
break;
|
|
/*case "text":
|
|
break;
|
|
case "light":
|
|
break;
|
|
case "composite":
|
|
break;
|
|
case "switch":
|
|
break;*/
|
|
/*case "fan":
|
|
break;
|
|
case "cover":
|
|
break;
|
|
case "lock":
|
|
break;
|
|
case "climate":
|
|
break;*/
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static async Task UpdateZigbee2MqttConfigAsync(string topic, string message, string userId, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService) {
|
|
// update zigbee2mqqtt config
|
|
switch (topic)
|
|
{
|
|
case "zigbee2mqtt/bridge/config/devices":
|
|
try
|
|
{
|
|
var devices = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(message);
|
|
var zigbee2mqttProvider = _ProviderDatabaseService.GetByType("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, _LocationDatabaseService, userId, filteredDevices, zigbee2mqttProvider);
|
|
}
|
|
|
|
System.Console.WriteLine($"Devices updated for user {userId}");
|
|
}
|
|
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("zigbee2mqtt");
|
|
|
|
if (zigbee2mqttProvider != null)
|
|
{
|
|
var groups = _GroupDatabaseService.GetByType(userId, "zigbee2mqtt");
|
|
// Compare the groups from MyCore and the group we received, if something diff in one group => Hard refresh (delete, new)
|
|
// TODO : wait for new devices
|
|
// GroupService.CompareGroupsFromZigbee2Mqtt(userId, groups, groupsConvert, _DeviceDatabaseService, _GroupDatabaseService);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during retrieving groups ! Exception: {ex}");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|