Wie ich meinen höhenverstellbaren Schreibtisch in einen IoT-Schreibtisch verwandelte

In diesem Artikel zeige ich Ihnen, wie ich meinen Schreibtisch mit manueller Höhe in einen automatisierten IoT-Schreibtisch verwandelt habe. Ich werde erläutern, wie Motoren dimensioniert und betrieben werden und wie Sie Ihr IoT-Gerät mithilfe von Heroku als öffentliche Schnittstelle mit Google verbinden.



Kurz gesagt, dieses Projekt hat zwei Funktionen. Erstens wird die Tabelle über Sprachbefehle von Google Smart Home mit Heroku verbunden, und zweitens: Heroku und die Tabelle selbst kommunizieren über das MQTT Internet of Things-Protokoll. MQTT ist eine gute Lösung für das Internet der Dinge sowie für die Überwindung einiger anderer Hindernisse, denen wir uns stellen müssen.



Zunächst möchte ich sagen, dass ich dieses Projekt nur zum Spaß gemacht habe. Ich hoffe, Sie finden diesen Artikel interessant und motivieren Sie, sich die Zeit zu nehmen, etwas Eigenes zu tun.



Der gleiche Tisch




Hardware-Teil



Der erste und wahrscheinlich schwierigste Teil der Arbeit ist die Neugestaltung der Tabelle. In einem früheren Leben hatte der Tisch einen abnehmbaren Griff, er befand sich am Rand der Tischplatte. Zuerst dachte ich darüber nach, etwas am Loch des Griffs anzubringen, ohne das Design des Tisches beeinträchtigen zu müssen. Ich habe mehrere Laufwerke gekauft, um herauszufinden, wie der Motor am Tisch befestigt werden kann, aber ohne Erfolg. Dann kam die Idee auf: eine Stange, die über die gesamte Länge des Tisches verläuft und die Beine so verbindet, dass sie gleichzeitig steigen und fallen. Wenn ich einen Antrieb anbringe, der zur Stange passt, kann ich die Stange mit einem Riemen mit dem Motor verbinden. Es wäre auch möglich, den Tisch mit einem Motor auszustatten, ohne das Design stark zu beeinträchtigen.



Die Bedeutung des Drehmoments



Nachdem ich den richtigen Antrieb und Riemen bestellt hatte, suchte ich bei Amazon nach einem Motor mit hohem Drehmoment. Und - oh, Wunder! - Ich habe viele passende Motoren gefunden! Zumindest schien es mir ... Nachdem ich einen kleinen Motor gekauft hatte, wartete ich ungefähr einen Monat auf seine Ankunft aus China. Ich war so aufgeregt, als der Motor endlich ankam! Ich konnte es kaum erwarten, dass das Wochenende endlich alles zusammensetzt und ich meinen motorisierten Schreibtisch habe.



Die Dinge liefen nicht nach Plan. Ich verbrachte den Tag damit, ein Loch für eine Stange in die Metallverkleidung des Tisches zu schneiden. Zu diesem Zeitpunkt hatte ich nur Handwerkzeuge, daher dauerte der Vorgang länger als erwartet. Gegen Ende des Tages war ich mit dem Zusammenbau des Tisches fertig und bereit, ihn auszuprobieren.



Ich habe den Motor eingeschaltet, die Spannung an meinem Desktop-Netzteil und ... nichts ist passiert. Ein paar Momente später begann sich der Motor zu drehen und die Zähne des erworbenen Riemens klapperten. Daraus habe ich zwei Lektionen gelernt: Der Riemen macht offensichtlich seine Arbeit nicht, und das Wort "Motor mit hohem Drehmoment" bedeutet nicht "Ich kann alles heben". Die zweite Lektion besteht darin, zu sehen, wie groß der Motor im Vergleich zu Ihren Fingern ist. Meins erwies sich als winzig!







Links auf dem Foto ist ein Motor und ein Riemen. Oben rechts ist ein Motor am Tisch angebracht (dazu später mehr). Unten rechts steht der Motor auf dem Tisch.



Geeigneter Motor



Um den richtigen Motor auszuwählen, musste berechnet werden, wie viel Drehmoment zum Anheben der Tischplatte erforderlich ist. Ich war überrascht, wie einfach das geht.







T=Fr







Das Drehmoment ist die Kraft multipliziert mit der Länge des Hebelarms.



Nun, ich hatte einen Hebelarm (dies ist ein Tischgriff), es war nur notwendig, die Kraft zu berechnen, die den Hebelarm leicht drehen würde. Ich lud den Tisch, indem ich den Milchkrug an den Griff band und nach und nach Wasser in den Krug gab, bis sich der Hebel zu drehen begann. Indem ich den Griff mit vollem Krug nach oben drehte, stellte ich sicher, dass das Gewicht den Griff leicht dreht. Ich fand, dass der Hebelarm 11 cm lang ist und die erforderliche Kraft 4 Pfund beträgt. Durch Einsetzen dieser Zahlen in die Formel stellte ich fest, dass der Motor ein Drehmoment von mindestens 19,95 kg / cm erzeugen muss. Und er fing an, ihn zu suchen.



Ich beschloss, den Tisch irreversibel neu zu gestalten. Ich wusste, dass die Stange, die durch die Mitte des Tisches ging, hohl war. Nachdem ich nach einem Doppelwellenmotor gesucht hatte, konnte ich die Stange abschneiden und mit dem Motor in der Mitte wieder zusammenbauen. Durch den Kauf von zwei Motoren mit einem Drehmoment von 20 kg / cm habe ich sichergestellt, dass genügend Drehmoment vorhanden ist, um den Tisch anzuheben.



An einem anderen schönen Samstag nahm ich meinen Tisch in vier Teile auseinander und sägte die Motorwellen, damit sie beim Zusammenbau der Stange verwendet werden konnten. Ich schob mehr Löcher in das Metall, um die Motoren zu passen. Diesmal gab es keinen Riemen: Die Motoren waren direkt mit der Stange verbunden, die Löcher waren ziemlich groß. Als der Abend hereinbrach, baute ich den Schreibtisch wieder zusammen und lud ihn mit Büromaterial auf.





Die beiden oberen Fotos sind Motoren, die vollständig auf dem Tisch montiert sind. Die beiden unteren Fotos sind eine integrierte Stange, die mit Hilfe von Motoren entlang der Tischlänge verläuft.



Ich habe die Motoren angeschlossen und an die Stromversorgung angeschlossen. Ich schaltete den Strom ein und sah, wie sich der Tisch bewegte! Diesmal war ich zuversichtlicher, weil ich die Motoren richtig dimensioniert habe. Ich habe zwar die Leistung der Motoren verdoppelt, aber es war erstaunlich zu sehen, wie sie sich bewegten!



Lassen Sie mich jedoch klarstellen, dass der Tisch langsam war. Ich habe ein Video gedreht, um einem Freund zu zeigen, wie der Tisch funktioniert, aber er musste die Zeitbeschleunigung für das Video aktivieren, um 5 Minuten lang nicht zu sehen, wie der Tisch die Tischposition ändert.



Der Umsatz ist wichtig. Endgültige Version



Schließlich wurde mir klar, dass alles auf zwei Dinge zurückzuführen ist: Drehmoment und Drehzahl. Es war notwendig, einen Motor mit einer ausreichenden Anzahl von Umdrehungen bei einem bereits bekannten Drehmoment zu finden.



Es war nicht so schwer. Obwohl ich keinen Doppelwellenmotor gefunden habe, habe ich ein rechteckiges Getriebe gefunden , das einen Einzelwellenmotor in einen Doppelwellenmotor umwandelt.



Kurz gesagt, der nächste Monat war ein Monat des Wartens auf ein Getriebe aus China, und am nächsten Samstag nach dem Warten hatte ich einen Tisch, der sich mit der richtigen Geschwindigkeit bewegte.





Der letzte Motor selbst befindet sich links und der installierte Motor befindet sich rechts. Wenig Hardware und viel Software.



Ich war nicht zufrieden mit dem riesigen Netzteil auf meinem Schreibtisch, das nur lag, um die Höhe der Tischplatte zu kontrollieren. Um die Position des Tisches von einem zum anderen und zurück zu ändern, habe ich außerdem die Drähte vertauscht. Kleines Problem, aber das Projekt wurde durchgeführt, um im Idealfall nur einen Knopf zu drücken und mehrere Höhenvoreinstellungen zu haben.



Bluetooth



Die erste Lösung bestand darin, der Tabelle Bluetooth hinzuzufügen. Letztendlich sieht es so aus, als ob fast jedes Gerät im Haus über Nluetooth verfügt, und das Telefon scheint eine praktische Steuerungsschnittstelle für so etwas wie meinen Schreibtisch zu sein.



Jetzt bekam ich eine Motorcontroller-Karte, eine nordische NRF52-Bluetooth-Karte, Abstandssensoren und fing an, an der Controller-Firmware herumzuspielen.



Am Ende des Artikels werde ich Links zu Software und Firmware hinterlassen, die ich für das Projekt geschrieben habe. Fühlen Sie sich frei, den Code zu kommentieren: Ich bin kein professioneller Firmware-Entwickler und möchte eine Anleitung erhalten.



Als kurze Einführung: ESP32 wurde in C ++ unter Verwendung von Arduino-Bibliotheken geschrieben, um mit der BLE Terminal-App auf dem Telefon zu interagieren. Die Installation und Konfiguration von BLE ist recht komplex. Zunächst müssen Sie alle Merkmale für die Werte erstellen, die Sie über BLE steuern möchten. Stellen Sie sich ein Merkmal als Variable in Ihrem Code vor. BLE umschließt eine Variable mit mehreren Handlern, um den Wert dieser Variablen abzurufen und festzulegen.



Die Merkmale werden dann in einen Dienst mit einer eigenen UUID gepackt, wodurch der Dienst für die Anwendung eindeutig und identifizierbar wird. Schließlich müssen Sie diesen Dienst zur Anzeigennutzlast hinzufügen, damit Ihr Dienst vom Gerät erkannt werden kann. Wenn ein Remote-Gerät eine Verbindung zu Ihrem Dienst herstellt und Daten über die Spezifikationen sendet, erkennt die Tabelle, dass der Benutzer die Höhe an eine andere Voreinstellung anpassen möchte, und beginnt sich zu bewegen.



Zur Höhenverstellung verfügt die Arbeitsplatte über einen TFMini-S LiDAR-Sensor, der die aktuelle Höhe erfasst. Dies ist ein lustiger Sensor: Er wird als LiDAR bezeichnet, wenn es sich tatsächlich um einen Laser handelt. Es verwendet Optiken und LEDs, um die Flugzeit der Infrarotstrahlung zu bestimmen. Auf die eine oder andere Weise bestimmt der Sensor die Höhe des Tisches. Die Steuerplatine erkennt dann die Differenz zwischen der aktuellen Höhe und der angeforderten Höhe und startet den Motor, der sich in die gewünschte Richtung dreht. Einige der Hauptteile des Codes sind unten aufgeführt, aber Sie können die gesamte Datei hier sehen .



void setup()
{
   Serial.begin(115200);
   Serial2.begin(TFMINIS_BAUDRATE);
   EEPROM.begin(3); // used for saving the height presets between reboots

   tfminis.begin(&Serial2);
   tfminis.setFrameRate(0);

   ledcSetup(UP_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
   ledcAttachPin(UP_PWM_PIN, UP_PWM_CHANNEL);

   ledcSetup(DOWN_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
   ledcAttachPin(DOWN_PWM_PIN, DOWN_PWM_CHANNEL);

   state_machine = new StateMachine();
   state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);

   BLEDevice::init("ESP32_Desk");
  ...

   BLEServer *p_server = BLEDevice::createServer();
   BLEService *p_service = p_server->createService(BLEUUID(SERVICE_UUID), 20);

   /* ------------------- SET HEIGHT TO PRESET CHARACTERISTIC -------------------------------------- */
   BLECharacteristic *p_set_height_to_preset_characteristic = p_service->createCharacteristic(...);
   p_set_height_to_preset_characteristic->setCallbacks(new SetHeightToPresetCallbacks());
   /* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
   BLECharacteristic *p_move_desk_up_characteristic = p_service->createCharacteristic(...);
   p_move_desk_up_characteristic->setCallbacks(new MoveDeskUpCallbacks());
   /* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
   BLECharacteristic *p_move_desk_down_characteristic = p_service->createCharacteristic(...);
   p_move_desk_down_characteristic->setCallbacks(new MoveDeskDownCallbacks());
   /* ------------------- GET/SET HEIGHT 1 CHARACTERISTIC ------------------------------------------ */
   BLECharacteristic *p_get_height_1_characteristic = p_service->createCharacteristic(...);
   p_get_height_1_characteristic->setValue(state_machine->getHeightPreset1(), 1);
   BLECharacteristic *p_save_current_height_as_height_1_characteristic = p_service->createCharacteristic(...);
   p_save_current_height_as_height_1_characteristic->setCallbacks(new SaveCurrentHeightAsHeight1Callbacks());
   /* ------------------- GET/SET HEIGHT 2 CHARACTERISTIC ------------------------------------------ */
  ...
   /* ------------------- GET/SET HEIGHT 3 CHARACTERISTIC ------------------------------------------ */
  ...
   /* ------------------- END CHARACTERISTIC DEFINITIONS ------------------------------------------ */
   p_service->start();

   BLEAdvertising *p_advertising = p_server->getAdvertising();
   p_advertising->start();

   xTaskCreate(
       updateDeskHeight,     // Function that should be called
       "Update Desk Height", // Name of the task (for debugging)
       1024,                 // Stack size
       NULL,                 // Parameter to pass
       5,                    // Task priority
       NULL                  // Task handle
   );
}
      
      





In der Datei ist noch viel mehr los, aber dieser Code hat genug Kontext, um zu verstehen, was los ist. Beachten Sie, dass wir alle BLE-Rückrufe für alle Merkmale erstellen und konfigurieren, einschließlich manueller Bewegung, Festlegen und Abrufen voreingestellter Werte und vor allem Ausrichten der Tabelle an der Voreinstellung.



Das Bild unten zeigt die Interaktion mit den Merkmalen zum Anpassen der Tischhöhe. Das letzte Puzzleteil ist eine Zustandsmaschine, die die aktuelle Tabellenhöhe und die vom Benutzer gewünschte Höhe kennt und mit diesen beiden Werten arbeitet.



Also hatte ich endlich einen Tisch, der tat, was ich wollte. Ich könnte die Höhe in Voreinstellungen speichern und die Höhen aus dem Speicher extrahieren, um die Tabelle auf meine Lieblingspositionen zu setzen. Ich habe BLE Terminal verwendetauf meinem Telefon und Computer, damit ich rohe Nachrichten an meinen Schreibtisch senden und dessen Position überwachen konnte. Es hat funktioniert, aber ich wusste, dass der Kampf mit BLE gerade erst begann.





Nackte Bluetooth-Oberfläche ... Im Moment



musste ich nur noch lernen, wie man Anwendungen für iOS schreibt ... Nach all dem sagte meine Frau etwas, das das gesamte Projekt veränderte: "Was ist, wenn Sie die Kontrolle über Ihre Stimme übernehmen?"



Sie müssen nicht nur cool sein und der Google Assistant-Liste ein neues Gerät hinzufügen, sondern auch keine iOS-Anwendung schreiben, um die Tabelle zu steuern. Und Sie mussten nicht mehr nach Ihrem Telefon greifen, um die Höhe anzupassen. Ein weiterer kleiner Sieg!



Das Internet der Dinge hinzufügen



Lassen Sie uns nun darüber sprechen, wie Sie Ihren Schreibtisch über Google Smart Home auf Sprachsteuerung umstellen und wie Sie ihn Wi-Fi-freundlich gestalten können.



Das Hinzufügen von Wi-Fi war einfach genug. Ich habe den nordischen NRF52-Mikrocontroller durch einen ESP32 mit integriertem WLAN ersetzt. Der größte Teil der Software war portabel, da sie in C ++ geschrieben war und beide Geräte mit Platform.IO und den Arduino-Bibliotheken programmiert werden konnten , einschließlich der tfmini-s, die ich zum Messen der aktuellen Tabellenhöhe geschrieben habe.



Die Architektur des Interaktionssystems der Tabelle mit Google Smart Home ist unten dargestellt. Lassen Sie uns über die Interaktion zwischen mir und Google sprechen.







Bluetooth wurde also aktiviert. Es ist Zeit herauszufinden, wie Sie mit Google Smart Home interagieren können. Diese Technologie kontrollierte das Haus mithilfe von Smart Home-Aktionen . Das Interessante an ihren Aktionen ist, dass der Dienst als OAuth2-Server und nicht als Client fungiert. Die meiste Arbeit mit dem Server bestand darin, eine OAuth2 Node.js Express-Anwendung zu implementieren, die nach Heroku gelangt und wie ein Proxy zwischen Google und meinem Schreibtisch kommuniziert.



Ich hatte Glück: Es gab eine anständige Serverimplementierung mit zwei Bibliotheken. Die erste Bibliothek, node-oauth2-server, wurde hier gefunden . Die zweite Express-Oauth-Server-Bibliothek für die Express-Verbindung wurde hier gefunden .



const { Pool } = require("pg");
const crypto = require("crypto");
const pool = new Pool({
   connectionString: process.env.DATABASE_URL
});

module.exports.pool = pool;
module.exports.getAccessToken = (bearerToken) => {...};
module.exports.getClient = (clientId, clientSecret) => {...};
module.exports.getRefreshToken = (bearerToken) => {...};
module.exports.getUser = (email, password) => {...};
module.exports.getUserFromAccessToken = (token) => {...};
module.exports.getDevicesFromUserId = (userId) => {...};
module.exports.getDevicesByUserIdAndIds = (userId, deviceIds) => {...};
module.exports.setDeviceHeight = (userId, deviceId, newCurrentHeight) => {...};
module.exports.createUser = (email, password) => {...};
module.exports.saveToken = (token, client, user) => {...};
module.exports.saveAuthorizationCode = (code, client, user) => {...};
module.exports.getAuthorizationCode = (code) => {...};
module.exports.revokeAuthorizationCode = (code) => {...};
module.exports.revokeToken = (code) => {...};

      
      





Als nächstes folgt die Konfiguration der Express-Anwendung. Nachfolgend sind die für einen OAuth-Server erforderlichen Endpunkte aufgeführt. Sie können jedoch die vollständige Datei hier lesen.



const express = require("express");
const OAuth2Server = require("express-oauth-server");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const flash = require("express-flash-2");
const session = require("express-session");
const pgSession = require("connect-pg-simple")(session);
const morgan = require("morgan");

const { google_actions_app } = require("./google_actions");
const model = require("./model");
const { getVariablesForAuthorization, getQueryStringForLogin } = require("./util");
const port = process.env.PORT || 3000;

// Create an Express application.
const app = express();
app.set("view engine", "pug");
app.use(morgan("dev"));

// Add OAuth server.
app.oauth = new OAuth2Server({
   model,
   debug: true,
});

// Add body parser.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static("public"));

// initialize cookie-parser to allow us access the cookies stored in the browser.
app.use(cookieParser(process.env.APP_KEY));

// initialize express-session to allow us track the logged-in user across sessions.
app.use(session({...}));

app.use(flash());

// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.
// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.
app.use((req, res, next) => {...});

// Post token.
app.post("/oauth/token", app.oauth.token());

// Get authorization.
app.get("/oauth/authorize", (req, res, next) => {...}, app.oauth.authorize({...}));

// Post authorization.
app.post("/oauth/authorize", function (req, res) {...});
app.get("/log-in", (req, res) => {...});
app.post("/log-in", async (req, res) => {...});
app.get("/log-out", (req, res) => {...});
app.get("/sign-up", async (req, res) => {...});
app.post("/sign-up", async (req, res) => {...});
app.post("/gaction/fulfillment", app.oauth.authenticate(), google_actions_app);
app.get('/healthz', ((req, res) => {...}));
app.listen(port, () => {
   console.log(`Example app listening at port ${port}`);
});
      
      





Es gibt ziemlich viel Code, aber ich werde die wichtigsten Punkte erklären. Die beiden für den Server verwendeten OAuth2-Routen sind / oauth / token und / oauth / authorize. Sie werden verwendet, um ein neues Token zu erhalten oder abgelaufene Token zu aktualisieren. Als Nächstes müssen Sie den Server auf die Aktion von Google reagieren lassen. Sie werden feststellen, dass der Endpunkt / gaction / erfüllung auf ein Objekt zeigt google_actions_app



.



Google sendet Anfragen in einem bestimmten Format an Ihren Server und stellt eine Bibliothek zur Verfügung, mit deren Hilfe diese Anfragen verarbeitet werden können. Nachfolgend finden Sie die Funktionen, die für die Kommunikation mit Google erforderlich sind. Die gesamte Datei befindet sich hier. Schließlich gibt es noch den Endpunkt / healthz, den ich am Ende des Artikels behandeln werde.



Der Endpunkt / gaction / Fulfillment verwendet eine Middleware namens app.oauth.authenticate (). Die harte Arbeit, den OAuth2-Server zum Laufen zu bringen, bestand darin, diese Middleware zum Laufen zu bringen. Es wird überprüft, ob das von Google bereitgestellte Inhaber-Token auf einen vorhandenen Benutzer verweist und nicht abgelaufen ist. Die Route sendet dann die Anforderung und Antwort an das Objekt google_actions_app



.



Google sendet Anfragen in einem bestimmten Format an Ihren Server und stellt eine Bibliothek zur Verfügung, mit deren Hilfe diese Anfragen analysiert und verarbeitet werden können. Im Folgenden finden Sie die Funktionen, die Sie benötigen, um mit Google Kontakt aufzunehmen. Sie können jedoch die gesamte Datei hier anzeigen .



const { smarthome } = require('actions-on-google');
const mqtt = require('mqtt');
const mqtt_client = mqtt.connect(process.env.CLOUDMQTT_URL);

const model = require('./model');
const { getTokenFromHeader } = require('./util');

mqtt_client.on('connect', () => {
   console.log('Connected to mqtt');
});

const updateHeight = {
   "preset one": (deviceId) => {
       mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "1");
   },
   "preset two": (deviceId) => {
       mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "2");
   },
   "preset three": (deviceId) => {
       mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "3");
   },
};

const google_actions_app = smarthome({...});
google_actions_app.onSync(async (body, headers) => {...});
google_actions_app.onQuery(async (body, headers) => {...});
google_actions_app.onExecute(async (body, headers) => {...});
module.exports = { google_actions_app };
      
      





Wenn Sie Ihrem Google-Konto eine intelligente Aktion hinzufügen, gibt Google eine Synchronisierungsanforderung aus. Diese Anfrage informiert Sie darüber, welche Geräte in Ihrem Konto verfügbar sind. Als Nächstes folgt eine Abfrageabfrage: Google fragt Ihre Geräte ab, um ihren aktuellen Status zu ermitteln.



Wenn Sie Ihrem Smart Home-Konto zum ersten Mal eine Google-Aktion hinzufügen, werden Sie feststellen, dass Google zuerst eine Synchronisierungsanforderung und dann eine Umfrageanforderung sendet, um eine ganzheitliche Ansicht Ihrer Geräte zu erhalten. Die letzte ist die Anfrage, eine Anfrage zu erfüllen, die Google Ihren Geräten anweist, etwas zu tun.



"Funktionen" (Merkmal) des Google Smart Home-Geräts



Google verwendet gerätespezifische Funktionen, um UI-Elemente für die Steuerung Ihrer Geräte für Google bereitzustellen und Kommunikationsvorlagen für die Sprachsteuerung zu erstellen. Einige der Funktionen umfassen die folgenden Einstellungen: ColorSetting, Modes, OnOff und StartStop. Ich habe eine Weile gebraucht, um zu entscheiden, welche Funktion in meiner Anwendung am besten funktioniert, aber später habe ich Modi ausgewählt.



Sie können sich Modi als Dropdown-Liste vorstellen, in der einer von N vordefinierten Werten oder in meinem Fall Höhenvoreinstellungen ausgewählt ist. Ich habe meinen Modus "Höhe" genannt und die möglichen Werte sind "voreingestellt eins", "voreingestellt zwei" und "voreingestellt drei". Auf diese Weise kann ich meinen Schreibtisch steuern, indem ich sage: "Hey Google, stellen Sie meine Schreibtischhöhe auf eine voreingestellte ein", und Google sendet eine entsprechende Ausführungsanforderung an mein System. Weitere Informationen zu den Funktionen von Google-Geräten finden Sie hier .



Projekt in Aktion



Schließlich begannen Google Smart Home und mein Computer zu kommunizieren. Vorher habe ich ngrok verwendet , um den Express-Server lokal auszuführen . Jetzt, da mein Server endlich gut genug funktioniert, ist es Zeit, ihn Google jederzeit zur Verfügung zu stellen. Daher musste die Anwendung auf Heroku gehostet werden. Dies ist ein PaaS-Anbieter, der die Bereitstellung und Verwaltung von Anwendungen erleichtert.



Einer der Hauptvorteile von Heroku ist der Add-On-Modus. Mit Add-Ons ist es sehr einfach, Ihrer Anwendung CloudMQTT- und Postgres-Server hinzuzufügen. Ein weiterer Vorteil der Verwendung von Heroku ist die einfache Montage und Bereitstellung. Heroku erkennt automatisch, welchen Code Sie verwenden, und erstellt / implementiert ihn für Sie. Weitere Informationen hierzu finden Sie unter Heroku Buildpacks . In meinem Fall werden bei jedem Push-Code an git remote Heroku alle meine Pakete installiert, alle Entwicklungsabhängigkeiten entfernt und die Anwendung mit einem einfachen Befehl "git push heroku main" bereitgestellt.



Mit nur wenigen Klicks standen CloudMQTT und Postgres für meine Anwendung zur Verfügung, und ich musste nur einige Umgebungsvariablen verwenden, um diese Dienste in meine Anwendung zu integrieren. Heroku bat um kein Geld. CloudMQTT ist jedoch ein Add-On eines Drittanbieters für 5 US-Dollar pro Monat.



Ich glaube, die Notwendigkeit von Postgres ist selbsterklärend, aber CloudMQTT verdient mehr Aufmerksamkeit.



Vom Internet zu einem privaten Netzwerk. Der harte Weg



Es gibt verschiedene Möglichkeiten, um Zugriff auf eine Anwendung oder in meinem Fall auf ein IoT-Gerät zu gewähren. Der erste besteht darin, einen Port in meinem Heimnetzwerk zu öffnen, um das Gerät ins Internet zu bringen. In diesem Fall sendet meine Heroku Express-App eine Anfrage unter Verwendung der öffentlichen IP-Adresse an mein Gerät. Dies würde erfordern, dass ich eine öffentliche statische IP sowie eine statische IP für den ESP32 habe. ESP32 müsste auch als HTTP-Server fungieren und ständig auf Anweisungen von Heroku warten. Dies ist ein großer Aufwand für ein Gerät, das mehrmals täglich Anweisungen erhält.



Die zweite Methode wird als Locher bezeichnet. Damit können Sie einen externen Server eines Drittanbieters verwenden, um auf das Gerät über das Internet zuzugreifen, ohne dass eine Portweiterleitung erforderlich ist. Ihr Gerät stellt im Grunde eine Verbindung zu einem Server her, der einen offenen Port einrichtet. Dann kann ein anderer Dienst eine direkte Verbindung zu Ihrem Backend herstellen, indem er einen offenen Port vom externen Server erhält. Schließlich wird über diesen offenen Port eine direkte Verbindung zum Gerät hergestellt. Der Ansatz kann ganz richtig sein oder auch nicht: Ich habe nur einen Teil des Artikels darüber gelesen.



Im "Locher" ist viel los, und ich verstehe nicht ganz, was passiert. Wenn Sie jedoch interessiert sind, gibt es einige interessante Artikel, die mehr erklären. Hier sind zwei Artikel, die ich gelesen habe, um den Locher besser zu verstehen: Wikipediaund ein Artikel vom MIT von Brian Ford und anderen .



Vom Internet zu einem privaten Netzwerk über das IoT



Ich war mit diesen Lösungen nicht sehr zufrieden. Ich habe viele intelligente Geräte an mein Zuhause angeschlossen und musste nie einen Port an meinem Router öffnen, sodass keine Portweiterleitung erfolgte. Außerdem scheint das Stanzen von Löchern viel schwieriger zu sein als das, wonach ich suche, und eignet sich besser für P2P-Netzwerke. Als Ergebnis weiterer Forschungen entdeckte ich MQTT und erfuhr, dass es sich um ein Protokoll für IoT handelt. Es bietet einige Vorteile wie einen geringen Stromverbrauch, eine konfigurierbare Fehlertoleranz und erfordert keine Portweiterleitung. MQTT ist ein Herausgeber- / Abonnentenprotokoll. Dies bedeutet, dass die Tabelle der Abonnent eines bestimmten Themas ist und die Heroku-Anwendung der Herausgeber dieses Themas ist.



Wenn Google Heroku kontaktiert, wird diese Anfrage analysiert, um das angeforderte Gerät und seinen neuen Status oder Modus zu ermitteln. Die Heroku-App veröffentlicht dann eine Nachricht an den CloudMQTT-Server, die als Add-On für Heroku bereitgestellt wird, und weist die Tabelle an, zur neuen Voreinstellung zu navigieren. Schließlich abonniert die Tabelle das Thema und erhält eine Nachricht, die von der Heroku-App gepostet wurde. Schließlich passt die Tabelle ihre Höhe wie gewünscht an! In der googleactionsapp-Datei werden Sie feststellen, dass es eine updateHeight-Funktion gibt, die eine MQTT-Nummer für eine bestimmte Geräte-ID veröffentlicht. Auf diese Weise veröffentlicht die Heroku-Anwendung eine Anforderung zum Verschieben von Tabellen an MQTT.



Der letzte Schritt besteht darin, die Nachricht auf dem ESP32 zu empfangen und die Tabelle zu verschieben. Ich werde Ihnen einige der Highlights des folgenden Tabellencodes zeigen, und der gesamte Quellcode ist hier .



void setup()
{
 Serial.begin(115200);
...
 tfminis.begin(&Serial2);
 tfminis.setFrameRate(0);

...

 state_machine = new StateMachine();
 state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);

 setup_wifi();

 client.setServer(MQTT_SERVER_DOMAIN, MQTT_SERVER_PORT);
 client.setCallback(callback);
...
}
      
      





Wenn der Tisch geladen ist, initiieren wir zuerst die Kommunikation zwischen dem TFMini-S - dem Abstandssensor -, um die aktuelle Tischhöhe zu erhalten. Dann richten wir die Zustandsmaschine für die Tischbewegung ein. Die Zustandsmaschine empfängt Befehle über MQTT und ist dann dafür verantwortlich, die Anforderung des Benutzers an die tatsächliche Tischhöhe anzupassen, die vom Abstandssensor gelesen wird. Schließlich stellen wir eine Verbindung zum Wi-Fi-Netzwerk her, stellen eine Verbindung zum MQTT-Server her und richten einen Rückruf für alle Daten ein, die zu dem von uns abonnierten MQTT-Thema empfangen wurden. Unten werde ich die Rückruffunktion zeigen.



void callback(char *topic, byte *message, unsigned int length)
{
 ...

 String messageTemp;

 for (int i = 0; i < length; i++)
 {
   messageTemp += (char)message[i];
 }

 if (messageTemp == "1") {
   state_machine->requestStateChange(ADJUST_TO_PRESET_1_HEIGHT_STATE);
 }

 if (messageTemp == "2") {
   state_machine->requestStateChange(ADJUST_TO_PRESET_2_HEIGHT_STATE);
 }

 if (messageTemp == "3") {
   state_machine->requestStateChange(ADJUST_TO_PRESET_3_HEIGHT_STATE);
 }
...
}
      
      





Die Zustandsmaschine registriert die im MQTT-Thema empfangene Zustandsänderung. Dann verarbeitet es den neuen Zustand in der Hauptschleife.



void loop()
{
 if (!client.connected())
 {
   reconnect();
 }
 client.loop();
 state_machine->processCurrentState();
}
      
      





Die Hauptschleife führt verschiedene Aktionen aus: Erstens stellt sie erneut eine Verbindung zum MQTT-Server her, sofern keine Verbindung besteht. Anschließend werden alle über das MQTT-Thema empfangenen Daten verarbeitet. Schließlich bewegt der Code die Tischplatte an den gewünschten Ort, der im MQTT-Thema angefordert wird.



Das ist alles! Der Tisch ist vollständig sprachgesteuert und kommuniziert mit Google, um Befehle zu erhalten!



Aktuelle Notizen



Der letzte Endpunkt, den ich nicht erwähnt habe, ist der Endpunkt / healthz. Dies liegt an der Tatsache, dass Google eine relativ schnelle Antwort erwartet und das Laden der Heroku-App bei jeder Anfrage in meinem Fall nicht funktioniert. Ich habe einen Ping-Service eingerichtet, um den / healthz-Endpunkt jede Minute zu pingen, damit der Service fehlerfrei und reaktionsbereit bleibt. Wenn Sie so etwas vorhaben, denken Sie daran, dass alle freien Stunden am Stand dafür aufgewendet werden. Jetzt ist alles in Ordnung: Dies ist die einzige Anwendung, die auf Heroku verwendet wird. Außerdem können Sie für 7 US-Dollar pro Monat auf Herokus Hobby-Plan upgraden , der die App am Laufen hält.



Das Erstellen eines IoT-Geräts ist am Anfang mit viel Aufwand verbunden. Ich entwarf die Hardware, erstellte das Steuerungsschema, konfigurierte den MQTT-Server, schrieb den Express OAuth2-Server und lernte, wie man durch Aktionen mit Google Smart Home interagiert. Der anfängliche Aufwand war enorm, aber ich habe das Gefühl, viel erreicht zu haben! Ganz zu schweigen davon, dass MQTT Server, Express OAuth2 Application Server und Google Smart Home-Aktionen für ein anderes Projekt verwendet werden können. Ich interessiere mich für Smart Homes und kann versuchen, mein Repertoire an IoT-Geräten um Sensoren zu erweitern, die verfolgen, was in meinem Haus passiert, und dies über MQTT melden. Sensoren zur Überwachung von Boden-, Temperatur- und Lichtsensoren sind sehr interessant zu überwachen und zu analysieren.



Was weiter?



Arbeitsplattenhöhen werden jetzt bestenfalls unzuverlässig gemessen. Ich verwende im Allgemeinen einen funktionierenden Infrarot-Abstandssensor TFMini-S. Es wurde festgestellt, dass sich die Höhe des Tisches während des Tages geringfügig ändert, wenn sich die Umgebungsbeleuchtung im Raum ändert. Ich bestellte einen Drehwinkelsensor, um die Umdrehungen einer Stange durch den Tisch zu berechnen. Dies sollte mir zu jeder Tageszeit eine genauere Bewegung ermöglichen. Ich habe auch Zugriff auf den Server, den ich im Keller hoste. Darauf kann ich meine eigenen Mosquitto MQTT-Server-, Node-RED- und OAuth2 Express-Anwendungen erkunden, wenn ich selbst etwas hosten möchte. Endlich ist die gesamte Elektronik direkt auf meinem Schreibtisch. Ich habe vor, die Geräte so zu organisieren, dass alles schön und ordentlich ist!



Vielen Dank für das Lesen des Artikels! Der Einfachheit halber gebe ich alle Links.




Bild









All Articles