Skip to content

Commit

Permalink
Improve ID input method in the keypad deleteKey command
Browse files Browse the repository at this point in the history
  • Loading branch information
hsakoh committed Aug 15, 2024
1 parent df15fe5 commit b2a8ac6
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 68 deletions.
2 changes: 1 addition & 1 deletion _build_on_haos/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "SwitchBot-Mqtt"
description: "Integrate SwitchBot Devices into Home Assistant via MQTT"
version: "1.0.20"
version: "1.0.21"
slug: "switchbot_mqtt"
url: "https://github.com/hsakoh/switchbot-mqtt"
ports:
Expand Down
2 changes: 1 addition & 1 deletion _compile_self/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "SwitchBot-Mqtt"
description: "Integrate SwitchBot Devices into Home Assistant via MQTT"
version: "1.0.20"
version: "1.0.21"
slug: "switchbot_mqtt"
url: "https://github.com/hsakoh/switchbot-mqtt"
ports:
Expand Down
2 changes: 1 addition & 1 deletion _docker-compose/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3.8'

services:
switchbot-mqtt:
image: ghcr.io/hsakoh/switchbotmqtt-amd64:1.0.20
image: ghcr.io/hsakoh/switchbotmqtt-amd64:1.0.21
volumes:
- ./:/data
ports:
Expand Down
31 changes: 31 additions & 0 deletions src/SwitchBotMqttApp/Models/Mqtt/MqttEntityHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public static string GetCommandParamObjectId(string deviceId, int commandIndex,
{
return $"{paramName}_{commandIndex}_cmd_{deviceId}";
}
public static string GetReloadKeysObjectId(string deviceId, int commandIndex, string paramName)
{
return $"{paramName}_{commandIndex}_reloadkeys_{deviceId}";
}

public static string GetCommandTemplate(CommandConfig commandConfig, string paramName, ParameterType? parameterType = null)
{
Expand Down Expand Up @@ -138,6 +142,33 @@ public static ButtonConfig CreateCommandButtonEntity(DeviceMqtt deviceMqtt, Devi
);
}

public static ButtonConfig CreateKeypadReloadButtonEntity(DeviceMqtt deviceMqtt, DeviceBase deviceConf, int commandIndex, CommandConfig command, CommandDefinition commandDef)
{
return new ButtonConfig(
deviceMqtt
, objectId: GetReloadKeysObjectId(deviceConf.DeviceId, commandIndex, ButtonPrefix)
, commandTopic: GetCommandTopic(deviceConf.DeviceId)
, commandTemplate: GetCommandTemplate(command, ButtonPrefix)
, payloadPress: "reloadkeys"
, name: "Reload keys"
, deviceClass: commandDef.ButtonDeviceClass
, icon: "mdi:refresh"
);
}

public static SelectConfig CreateKeypadDeleteKeySelectEntity(DeviceBase deviceConf, int commandIndex, CommandConfig command, DeviceMqtt deviceMqtt, CommandPayloadDefinition paramDef, string[] options)
{
return new SelectConfig(
deviceMqtt
, defaultValue: ""
, objectId: GetCommandParamObjectId(deviceConf.DeviceId, commandIndex, paramDef.Name)
, commandTopic: GetCommandTopic(deviceConf.DeviceId)
, commandTemplate: GetCommandTemplate(command, paramDef.Name, paramDef.ParameterType)
, name: paramDef.Name
, options: options
);
}

public static ButtonConfig CreateSensorUpdateButtonEntity(DeviceMqtt deviceMqtt, PhysicalDevice physicalDevice)
{
return new ButtonConfig(
Expand Down
195 changes: 130 additions & 65 deletions src/SwitchBotMqttApp/Services/MqttCoreService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HomeAssistantAddOn.Mqtt;
using CliWrap;
using HomeAssistantAddOn.Mqtt;
using SwitchBotMqttApp.Logics;
using SwitchBotMqttApp.Models.DeviceConfiguration;
using SwitchBotMqttApp.Models.DeviceDefinitions;
Expand All @@ -8,6 +9,7 @@
using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Nodes;
using static HomeAssistantAddOn.Mqtt.SupervisorApi;

namespace SwitchBotMqttApp.Services;

Expand Down Expand Up @@ -197,6 +199,31 @@ private async Task PublishCommandEntities(DeviceMqtt deviceMqtt, DeviceBase devi
};
}

// Keypad deleteKey
if ((deviceConf.DeviceType == DeviceType.Keypad
|| deviceConf.DeviceType == DeviceType.KeypadTouch)
&& command.Command == "deleteKey")
{
var deviceMqttForCommand = new DeviceMqtt(
identifiers: [$"{deviceConf.DeviceId}{command.Command}"],
name: $"{deviceConf.DeviceName}-{command.Command}",
manufacturer: deviceMqtt.Manufacturer,
model: deviceMqtt.Model);
commandDeviceEntities.Add(deviceMqttForCommand);
buttonEntities.Add(MqttEntityHelper.CreateCommandButtonEntity(deviceMqttForCommand, deviceConf, commandIndex, command, commandDef));
buttonEntities.Add(MqttEntityHelper.CreateKeypadReloadButtonEntity(deviceMqttForCommand, deviceConf, commandIndex, command, commandDef));

var paramDef = deviceDefinitionsManager.CommandPayloadDefinitions.Where(c => c.DeviceType == deviceConf.DeviceType && c.CommandType == command.CommandType && c.Command == command.Command).First();
var payloadDict = CommandPayloadDictionary.GetOrAdd(deviceConf.DeviceId, new ConcurrentDictionary<string, object>());

var (response, responseRaw) = await switchBotApiClient.GetDevicesAsync(CancellationToken.None);
var deivce = response.DeviceList.Where(rd => rd!.DeviceId == deviceConf.DeviceId).FirstOrDefault();
var keys = deivce!.KeyList.Select(key => $"{key.Id}:{key.Name}:{key.Type}").ToArray();
selectEntities.Add(MqttEntityHelper.CreateKeypadDeleteKeySelectEntity(deviceConf, commandIndex, command, deviceMqttForCommand, paramDef, keys));
payloadDict[paramDef.Name] = "";
break;
}

switch (commandDef.PayloadType)
{
case PayloadType.SingleValue:
Expand Down Expand Up @@ -295,6 +322,42 @@ private async Task ReceiveCommandAsync(string payloadRaw, DeviceBase device)
return;
}

// Keypad deleteKey
if ((device.DeviceType == DeviceType.Keypad
|| device.DeviceType == DeviceType.KeypadTouch)
&& payload.Command == "deleteKey")
{
if (payload.ParamValue == "reloadkeys")
{
var paramDef = deviceDefinitionsManager.CommandPayloadDefinitions.Where(c => c.DeviceType == device.DeviceType && c.CommandType == commandType && c.Command == payload.Command).First();
var payloadDict = CommandPayloadDictionary.GetOrAdd(device.DeviceId, new ConcurrentDictionary<string, object>());

var (response, responseRaw) = await switchBotApiClient.GetDevicesAsync(CancellationToken.None);
var deivce = response.DeviceList.Where(rd => rd!.DeviceId == device.DeviceId).FirstOrDefault();
var keys = deivce!.KeyList.Select(key => $"{key.Id}:{key.Name}:{key.Type}").ToArray();
var commandIndex = device.Commands.Where(c => c.Enable).ToList().IndexOf(commandConf) + 1;

var deviceMqtt = new DeviceMqtt(
identifiers: [device.DeviceId],
name: device.DeviceName,
manufacturer: $"SwitchBot",
model: deviceDefinitionsManager.DeviceDefinitions.First(x => x.DeviceType == device.DeviceType).ApiDeviceTypeString);
var deviceMqttForCommand = new DeviceMqtt(
identifiers: [$"{device.DeviceId}{commandDef!.Command}"],
name: $"{device.DeviceName}-{commandDef.Command}",
manufacturer: deviceMqtt.Manufacturer,
model: deviceMqtt.Model);
await PublishEntityAsync(MqttEntityHelper.CreateKeypadDeleteKeySelectEntity(device, commandIndex, commandConf, deviceMqttForCommand, paramDef, keys), true);
payloadDict[paramDef.Name] = "";
return;
}
if (payload.ParamName == "id")
{
CommandPayloadDictionary[device.DeviceId][payload.ParamName] = payload.ParamValue.Split(':').FirstOrDefault() ?? "";
return;
}
}

if (payload.ParamName != MqttEntityHelper.ButtonPrefix)
{
CommandPayloadDictionary[device.DeviceId][payload.ParamName] = payload.ParamValue;
Expand All @@ -307,91 +370,93 @@ private async Task ReceiveCommandAsync(string payloadRaw, DeviceBase device)
await switchBotApiClient.SendDefaultDeviceControlCommandAsync(device, commandConf, CancellationToken.None);
return;
}
var paramDefs = deviceDefinitionsManager.CommandPayloadDefinitions.Where(p => p.DeviceType == device.DeviceType && p.CommandType == commandType && p.Command == payload.Command).OrderBy(p => p.Index).ToList();
var payloadDict = CommandPayloadDictionary.GetOrAdd(device.DeviceId, new ConcurrentDictionary<string, object>());
if (commandDef.PayloadType == PayloadType.SingleValue)
{
await switchBotApiClient.SendDeviceControlCommandAsync(device, commandConf, payloadDict[paramDefs[0].Name], CancellationToken.None);
return;
}

if (commandDef.PayloadType == PayloadType.Json)
{
var jsonRoot = JsonNode.Parse("{}")!;
paramDefs.ForEach(paramDef =>
var paramDefs = deviceDefinitionsManager.CommandPayloadDefinitions.Where(p => p.DeviceType == device.DeviceType && p.CommandType == commandType && p.Command == payload.Command).OrderBy(p => p.Index).ToList();
var payloadDict = CommandPayloadDictionary.GetOrAdd(device.DeviceId, new ConcurrentDictionary<string, object>());
if (commandDef.PayloadType == PayloadType.SingleValue)
{
var json = jsonRoot;
if (!string.IsNullOrEmpty(paramDef.Path))
{
if (jsonRoot[paramDef.Path] == null)
{
jsonRoot[paramDef.Path] = JsonNode.Parse("{}")!;
}
json = jsonRoot[paramDef.Path]!;
}
if (paramDef.ParameterType == ParameterType.Long
|| paramDef.ParameterType == ParameterType.Range)
await switchBotApiClient.SendDeviceControlCommandAsync(device, commandConf, payloadDict[paramDefs[0].Name], CancellationToken.None);
return;
}

if (commandDef.PayloadType == PayloadType.Json)
{
var jsonRoot = JsonNode.Parse("{}")!;
paramDefs.ForEach(paramDef =>
{
if (long.TryParse((string)payloadDict[paramDef.Name], out var longValue)
&& longValue != paramDef.RangeMin - 1)
var json = jsonRoot;
if (!string.IsNullOrEmpty(paramDef.Path))
{
json[paramDef.Name] = JsonValue.Create<long>(longValue);
if (jsonRoot[paramDef.Path] == null)
{
jsonRoot[paramDef.Path] = JsonNode.Parse("{}")!;
}
json = jsonRoot[paramDef.Path]!;
}
}
else if (paramDef.ParameterType == ParameterType.Select)
{
json[paramDef.Name] = paramDef.DescriptionToOption((string)payloadDict[paramDef.Name]);
}
else if (paramDef.ParameterType == ParameterType.SelectOrRange)
{
if (long.TryParse((string)payloadDict[paramDef.Name], out var longValue))
if (paramDef.ParameterType == ParameterType.Long
|| paramDef.ParameterType == ParameterType.Range)
{
json[paramDef.Name] = JsonValue.Create<long>(longValue);
if (long.TryParse((string)payloadDict[paramDef.Name], out var longValue)
&& longValue != paramDef.RangeMin - 1)
{
json[paramDef.Name] = JsonValue.Create<long>(longValue);
}
}
else
else if (paramDef.ParameterType == ParameterType.Select)
{
json[paramDef.Name] = paramDef.DescriptionToOption((string)payloadDict[paramDef.Name]);
}
}
else
{
json[paramDef.Name] = JsonValue.Create<string>((string)payloadDict[paramDef.Name]);
}
});
await switchBotApiClient.SendDeviceControlCommandAsync(device, commandConf, jsonRoot, CancellationToken.None);
}
else
{
var parameters = string.Join(
commandDef.PayloadType switch
{
PayloadType.JoinColon => ':',
PayloadType.JoinComma => ',',
PayloadType.JoinSemiColon => ':',
_ => throw new InvalidOperationException()
}
, paramDefs.Select(p =>
{
if (p.ParameterType == ParameterType.SelectOrRange)
else if (paramDef.ParameterType == ParameterType.SelectOrRange)
{
if (long.TryParse((string)payloadDict[p.Name], out var longValue))
if (long.TryParse((string)payloadDict[paramDef.Name], out var longValue))
{
return longValue;
json[paramDef.Name] = JsonValue.Create<long>(longValue);
}
else
{
return p.DescriptionToOption((string)payloadDict[p.Name]);
json[paramDef.Name] = paramDef.DescriptionToOption((string)payloadDict[paramDef.Name]);
}
}
if (p.ParameterType == ParameterType.Select)
else
{
return p.DescriptionToOption((string)payloadDict[p.Name]);
json[paramDef.Name] = JsonValue.Create<string>((string)payloadDict[paramDef.Name]);
}
return payloadDict[p.Name];
}));
await switchBotApiClient.SendDeviceControlCommandAsync(device, commandConf, parameters, CancellationToken.None);
});
await switchBotApiClient.SendDeviceControlCommandAsync(device, commandConf, jsonRoot, CancellationToken.None);
}
else
{
var parameters = string.Join(
commandDef.PayloadType switch
{
PayloadType.JoinColon => ':',
PayloadType.JoinComma => ',',
PayloadType.JoinSemiColon => ':',
_ => throw new InvalidOperationException()
}
, paramDefs.Select(p =>
{
if (p.ParameterType == ParameterType.SelectOrRange)
{
if (long.TryParse((string)payloadDict[p.Name], out var longValue))
{
return longValue;
}
else
{
return p.DescriptionToOption((string)payloadDict[p.Name]);
}
}
if (p.ParameterType == ParameterType.Select)
{
return p.DescriptionToOption((string)payloadDict[p.Name]);
}
return payloadDict[p.Name];
}));
await switchBotApiClient.SendDeviceControlCommandAsync(device, commandConf, parameters, CancellationToken.None);
}
}

}
catch (Exception e)
{
Expand Down

0 comments on commit b2a8ac6

Please sign in to comment.