Avant d'aller plus loin, je tiens à apporter quelque précision sur ma démarche:
Ce post n'est pas à objectif pédagogique. Je ne suis pas un professionnel et je me suis adapté en fonction de mes connaissances, du matériel à ma disposition et du temps qui m'étais imparti.
Ce post, donc, est une explication de ma mise en place pour le sujet qui m'a été donné. Il sera plein de fautes, incomplet certainement voir même offrera des solutions plus compliqué que ce qu'il devrai être.
J'espère tout de même que ma démarche aidera d'autres personnes à imaginer de meilleur solution et dégrossira les difficultés qui peuvent être rencontré.
Merci à vous <3
Ps: C'est la 2e partie de mes recherhes. La partie 1 se trouve ici
Comment j'ai controlé les lumieres BLE Triones avec un Streamdeck (Partie 2)
Mise en place d'un Raspberry pi pour le controle Bluetooth des lumières
Après plusieurs essaie, j'ai décidé de me servir d'un systeme Linux pour communiqué avec les lumières à l'aide de la librairie intégrée Bluez. Cette librairie m'a permis en quelques lignes de commandes de découvrir mon réseau, me connecter et communiquer.
TODO : Détailler les opérations liés a l'installation, le scan, la connexion et les data
TODO : parler de la connection ssh + test coté windows avec streamdeck
Création du plugin Streamdeck en C
Préparation
Pour cette partie, j'ai simplement suivi le tuto de Claudio Bernasconi pour créer un plugin pour Streamdeck en C# avec Toolkit.
Pour ce faire :
- Installez les pré-requis pour le "Streamdeck Toolkit", A savoir le Dotnet Core SDK et l'application "Streamdeck Software".
- Installez également Visual studio 2019 Community edition pour gérer le projet et pouvoir le compiler.
Ouvre votre console préférée, rendez vous dans votre dossier de projet et tapez la ligne suivante:
dotnet new -i StreamDeckPluginTemplate::0.5.2040
- Créez le dossier de votre projet. (pour moi ça sera BtTrionesBLELightStreamdeckPlugin)
mkdir BtTrionesBLELightStreamdeckPlugin
Entrez dedans
cd BtTrionesBLELightStreamdeckPlugin
-
Saisissez la ligne suivante pour télécharger le template de création
dotnet new streamdeck-plugin --plugin-name StreamdeckPluginTrionesBleLights --uuid com.khundar.streamdecktrionesblelights --skipRestore false
. Attention à adapter le "plugin-name" et l'uuid.L'uuid est important pour que l'application streamdeck reconnaisse votre plugin.
Ouvrez le projet avec Visual Studio 2019 avec "Ouvrir un projet ou une solution" et sélectionnez le fichier BtTrionesBLELightStreamdeckPlugin.csproj
Vous voici dans le projet Template. Il "ne reste plus qu'à..."
Objectif 1: envoyer une commande
Mon but à ce moment-ci est d'effectuer la connexion ssh et lancer gatttool.
Pour exécuter une commande shell, j'ai trouvé cette façon de faire :
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + bashCmd);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
process.Close();
Ensuite, pour effectuer ma commande de manipulation de la lumière, je remplace la variable bashCmd
string lightMacAddr = "ff:ff:11:11:bb:9b"; //adresse de la lumiere
string switch = "cc2333"; //commande d'allumage
string color = "ff0000";
string sshconnect = "ssh pi@192.168.0.32"; //Connexion ssh
string stophci = "sudo hciconfig hci0 down"; //fermeture de la connexion bluetooth
string starthci = "sudo hciconfig hci0 up"; //fermeture de la connexion bluetooth
string gatttoolpwr = "sudo gatttool -b " + lightMacAddr + " --char-write-req --handle=0x0007 --value=" + switch;
string gatttoolcolor = "sudo gatttool -b " + lightMacAddr + " --char-write-req --handle=0x0007 --value=56" + color + "00f0aa";
string bashCmd = "\"" + stophci + " && " + starthci + " && " + gatttoolpwr + " && " + gatttoolcolor + " && " + stophci + "\"";
Pour finir, je souhaite effectuer la commande sur un "keyup". Celle déjà en place suffira:
// ./StreamdeckPluginTrionesBleLightsAction.cs
public override async Task OnKeyUp(StreamDeckEventPayload args)
{
string lightMacAddr = "ff:ff:11:11:bb:9b"; //adresse de la lumiere
string switch = "cc2333"; //commande d'allumage
string color = "ff0000";
string sshconnect = "ssh pi@192.168.0.32"; //Connexion ssh
string stophci = "sudo hciconfig hci0 down"; //fermeture de la connexion bluetooth
string starthci = "sudo hciconfig hci0 up"; //fermeture de la connexion bluetooth
string gatttoolpwr = "sudo gatttool -b " + lightMacAddr + " --char-write-req --handle=0x0007 --value=" + switch;
string gatttoolcolor = "sudo gatttool -b " + lightMacAddr + " --char-write-req --handle=0x0007 --value=56" + color + "00f0aa";
string bashCmd = "\"" + stophci + " && " + starthci + " && " + gatttoolpwr + " && " + gatttoolcolor + " && " + stophci + "\"";
processInfo = new ProcessStartInfo("cmd.exe", "/c " + sshconnect + " " + bashCmd);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
process.Close();
//update settings
await Manager.SetSettingsAsync(args.context, SettingsModel);
}
Très bien, mon action est prête.
Objectif 2: Dynamiser cette commande
À présent, isolons les variables nécessaires à la configuration d'une lumière :
- l'adresse MAC de la lumière => lightMacAddr
- l'état de la lumière => switch
- la couleur => color
Commençons par modifier le model
// ./models/TrionesBLESettingsModel.cs
namespace StreamdeckPluginTrionesBleLights.Models
{
public class TrionesBLESettingsModel
{
public string Switch { get; set; } = "000000";
public string Color { get; set; } = "000000";
public string LightMacAddr { get; set; } = "xx:xx:xx:xx:xx:xx";
}
}
Ensuite, on ajoute les attributs du model dans le controleur.
// ./StreamdeckPluginTrionesBleLightsAction.cs
public override async Task OnKeyUp(StreamDeckEventPayload args)
{
string lightMacAddr = SettingsModel.LightMacAddr; //adresse de la lumiere
string switch = SettingsModel.LightMacAddr; //commande d'allumage
string color = SettingsModel.Color;
string sshconnect = "ssh pi@192.168.0.32"; //Connexion ssh
string stophci = "sudo hciconfig hci0 down"; //fermeture de la connexion bluetooth
string starthci = "sudo hciconfig hci0 up"; //fermeture de la connexion bluetooth
string gatttoolpwr = "sudo gatttool -b " + lightMacAddr + " --char-write-req --handle=0x0007 --value=" + switch;
string gatttoolcolor = "sudo gatttool -b " + lightMacAddr + " --char-write-req --handle=0x0007 --value=56" + color + "00f0aa";
string bashCmd = "\"" + stophci + " && " + starthci + " && " + gatttoolpwr + " && " + gatttoolcolor + " && " + stophci + "\"";
processInfo = new ProcessStartInfo("cmd.exe", "/c " + sshconnect + " " + bashCmd);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
process.Close();
//update settings
await Manager.SetSettingsAsync(args.context, SettingsModel);
}
Et on fini avec la vue.
<!-- ./property_inspector/property_inspector.html -->
<body>
<div class="sdpi-wrapper">
<!-- select light -->
<div class="sdpi-item" id="select_light">
<div class="sdpi-item-label">Lights</div>
<select class="sdpi-item-value select" id="light" onchange="setSettings(event.target.value, 'LightMacAddr');">
<option value="xx:xx:xx:xx:xx:xx">--Select a light--</option>
<option value="ff:ff:11:11:bb:9b" data-name="Light 1">Light 1</option>
<option value="ff:ff:50:03:10:3c" data-name="Light 2">Light 2</option>
<option value="ff:ff:66:60:cf:58" data-name="Light 3">Light 3</option>
<option value="ff:ff:77:70:b1:a4" data-name="Light 4">Light 4</option>
<option value="ff:ff:33:30:fe:ee" data-name="Light 5">Light 5</option>
<option value="ff:ff:44:42:77:82" data-name="Light 6">Light 6</option>
</select>
</div>
<!-- switch on/off -->
<div class="sdpi-item" id="select_switch">
<div class="sdpi-item-label">Switch</div>
<select class="sdpi-item-value select" id="switch" onchange="setSettings(event.target.value, 'Switch')">
<option value="cc2333">ON</option>
<option value="cc2433">OFF</option>
<option value="000000">--Select a Power--</option>
</select>
</div>
<!-- color -->
<div type="range" class="sdpi-item" id="colorslider" onchange="setSettings(event.target.value, 'Color')">
<div class="sdpi-item-label">Color</div>
<div class="sdpi-item-value">
<input type="color" id="color" value="#000000">
</div>
</div>
</div>
<script src="js/property-inspector.js"></script>
</body>
et le js
// global websocket, used to communicate from/to Stream Deck software
// as well as some info about our plugin, as sent by Stream Deck software
var websocket = null,
uuid = null,
inInfo = null,
actionInfo = {},
settingsModel = {
LightMacAddr: 'xx:xx:xx:xx:xx:xx',
Switch: '000000',
Color: '000000'
};
function connectElgatoStreamDeckSocket(inPort, inUUID, inRegisterEvent, inInfo, inActionInfo) {
uuid = inUUID;
actionInfo = JSON.parse(inActionInfo);
inInfo = JSON.parse(inInfo);
websocket = new WebSocket('ws://localhost:' + inPort);
//initialize values
if (actionInfo.payload.settings.settingsModel) {
settingsModel.LightMacAddr = actionInfo.payload.settings.settingsModel.LightMacAddr;
settingsModel.Switch = actionInfo.payload.settings.settingsModel.Switch;
settingsModel.Color = actionInfo.payload.settings.settingsModel.Color;
settingsModel.Name = actionInfo.payload.settings.settingsModel.Name;
}
websocket.onopen = function () {
console.log(settingsModel);
setSelectField('light', settingsModel.LightMacAddr);
setSelectField('switch', settingsModel.Switch);
document.getElementById("color").value = '#' + settingsModel.Color;
var json = { event: inRegisterEvent, uuid: inUUID };
// register property inspector to Stream Deck
websocket.send(JSON.stringify(json));
};
websocket.onmessage = function (evt) {
// Received message from Stream Deck
var jsonObj = JSON.parse(evt.data);
var sdEvent = jsonObj['event'];
switch (sdEvent) {
case "didReceiveSettings":
break;
default:
break;
}
};
function setSelectField(id, value) {
var allInputs = document.getElementById(id);
for (var x = 0; x < allInputs.length; x++)
if (allInputs[x].value == value) {
allInputs[x].setAttribute('selected', 'selected');
console.log(allInputs[x]);
}
}
}
const setSettings = (value, param) => {
console.log(param + "=" + value);
if (websocket) {
if (param == 'Color')
value = value.substring(1);
settingsModel[param] = value;
var json = {
"event": "setSettings",
"context": uuid,
"payload": {
"settingsModel": settingsModel
}
};
websocket.send(JSON.stringify(json));
}
};
A présent, mon plugin est prêt à être utiliser
Top comments (0)