261 lines
11 KiB
C#

using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MyCore.Interfaces.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using YeelightAPI;
namespace MyCore.Services
{
public class MQTTService
{
private IMqttClient _client;
private IMqttClientOptions _options;
private string _mqttServer = "192.168.31.140";
private string _user = "mqtt";
private string _password = "mqtt";
private LightState lightStateIkeaBulb = LightState.Undefined;
public List<Zigbee2MqttDevice> devices = new List<Zigbee2MqttDevice>();
// It's here to have the mqtt initialisation + logic for payload..
// Related to which event occurs, a specific action is done.
private YeelightService yeelightService = new YeelightService();
public MQTTService(string server, string user, string password)
{
try
{
_mqttServer = server;
_user = user;
_password = password;
// Create a new MQTT client.
_client = new MqttFactory().CreateMqttClient();
_options = new MqttClientOptionsBuilder()
.WithClientId("ApiService")
.WithTcpServer(_mqttServer)
.WithCredentials(_user, _password)
.WithCleanSession()
.Build();
_client.ConnectAsync(_options, CancellationToken.None).ContinueWith(res => {
if (res.Status == TaskStatus.RanToCompletion)
{
Console.WriteLine("It's connected");
PublishMessage("zigbee2mqtt/bridge/config/devices/get", "");
}
else
{
Console.WriteLine($"Error connecting to {_mqttServer}");
throw new UnauthorizedAccessException("Error connecting to mqtt server: " + _mqttServer);
}
});
_client.UseDisconnectedHandler(async e =>
{
Console.WriteLine("### DISCONNECTED FROM SERVER ###");
await Task.Delay(TimeSpan.FromSeconds(5));
try
{
await _client.ConnectAsync(_options, CancellationToken.None); // Since 3.0.5 with CancellationToken
}
catch
{
Console.WriteLine("### RECONNECTING FAILED ###");
}
});
_client.UseConnectedHandler(async e =>
{
Console.WriteLine("### CONNECTED WITH SERVER ###");
// Subscribe to a topic
await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
Console.WriteLine("### SUBSCRIBED ###");
});
_client.UseApplicationMessageReceivedHandler(e =>
{
Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###");
Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}");
var payload = "";
if (e.ApplicationMessage.Payload != null)
{
Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
}
Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}");
Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}");
Console.WriteLine();
var topic = e.ApplicationMessage.Topic;
// As soon as we received all the info =>
//_client.DisconnectAsync();
// TODO
// Here take only zigbee2mqtt *
// Check if we have the guid in database
// If so retrieve the device in database and his Type
// Retrieve the device as an object (We have a defined list of devices. That's not a problem, it's a choice as we want reliability)
// Check in the list of automations if we have something to do with the message (Check in mqtt input section)
// Automation = id, name,
// Load everydevice in cache.. ? Performance ?
// TODO - TO CLARIFY
switch (topic)
{
case "zigbee2mqtt/bridge/config/devices":
try
{
var test = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(payload);
devices = test;
// TODO Update in DB, current devices state
}
catch (Exception ex)
{
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
}
break;
case "zigbee2mqtt/0x00158d00029a7b65":
try
{
var test = JsonConvert.DeserializeObject<AqaraCube>(payload);
if (test.Action == "shake")
{
/*var labLamp = yeelightService.devices.Where(d => d.Hostname == "192.168.31.74").FirstOrDefault();
Task.Run(async () => { await yeelightService.Toggle(labLamp); });*/
}
if (test.Action == "slide")
{
if (lightStateIkeaBulb == LightState.Undefined || lightStateIkeaBulb == LightState.Off)
PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"ON\"}");
else
PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"OFF\"}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error cube ! Exception: {ex}");
}
break;
case "zigbee2mqtt/0x14b457fffe7628fa":
try
{
var lightState = JsonConvert.DeserializeObject<LightBulb>(payload);
if (lightState.State == "ON")
lightStateIkeaBulb = LightState.On;
else
lightStateIkeaBulb = LightState.Off;
}
catch (Exception ex)
{
Console.WriteLine($"Error IkeaLightBulb ! Exception: {ex}");
}
break;
case "zigbee2mqtt/0x00158d00035cf1a7":
try
{
var aqaraSwitch = JsonConvert.DeserializeObject<AqaraSwitch>(payload);
if (aqaraSwitch.Click == "single") {
YeelightService yeelighService = new YeelightService();
// var devicesYeelight = yeelighService.GetDevices().Result;
// var labLamp = devicesYeelight.Where(light => light.Hostname == "192.168.31.74").FirstOrDefault();
//if (labLamp != null) { }
// yeelightService.Toggle(labLamp);
}
if (aqaraSwitch.Click == "double")
{
if (lightStateIkeaBulb == LightState.Undefined || lightStateIkeaBulb == LightState.Off)
PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"ON\"}");
else
PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"OFF\"}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error Aqara switch ! Exception: {ex}");
}
break;
default:
Console.WriteLine("Hello nothing to do here..");
break;
}
});
}
catch (Exception e)
{
Console.WriteLine($"Error during creation of MQTTService with {_mqttServer}, exceptions : {e}");
}
}
public async void PublishMessage(string topic, string message)
{
var mqttMessage = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(message)
.WithExactlyOnceQoS()
.WithRetainFlag()
.Build();
if (_client.IsConnected)
await _client.PublishAsync(mqttMessage);
}
public List<Zigbee2MqttDevice> GetDevices()
{
return devices;
}
/*protected async Task Start()
{
var server = new MqttFactory().CreateMqttServer();
try
{
var client1 = new MqttFactory().CreateMqttClient();
await client1.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer(_mqttServer).Build());
var message = new MqttApplicationMessageBuilder().WithPayload("It's a test").WithTopic("IpAddress").WithRetainFlag().Build();
await client1.PublishAsync(message);
await Task.Delay(500);
}
finally
{
await server.StopAsync();
}
}*/
}
}