Ein Hersteller von Netzwerkgeräten in Shenzhen, China, dessen Hauptgeschäft Router sind. In den letzten Jahren haben wir uns auf IoT-Haushaltsgeräte wie intelligente Glühbirnen und intelligente Stecker konzentriert und aufgrund der guten Kostenleistung eine einzigartige Position bei Amazon aufgebaut.
[Smart Plug HS105](https://www.amazon.co.jp/Alexa%E8%AA%8D%E5%AE%9A%E5%8F%96%E5%BE%97%E8%A3%BD % E5% 93% 81% E3% 80% 91-% E7% 9B% B4% E5% B7% AE% E3% 81% 97% E3% 82% B3% E3% 83% B3% E3% 82% BB% E3% 83% B3% E3% 83% 88-Google% E3% 83% 9B% E3% 83% BC% E3% 83% A0% E5% AF% BE% E5% BF% 9C-% E9% 9F% B3 % E5% A3% B0% E3% 82% B3% E3% 83% B3% E3% 83% 88% E3% 83% AD% E3% 83% BC% E3% 83% AB-HS105 / dp / B078HSBNMT? Ref_ = ast_sto_dp)
[Intelligente Glühbirne KL110](https://www.amazon.co.jp/%E3%80%90Amazon-Alexa%E8%AA%8D%E5%AE%9A-%E3%80%91TP-Link-KL110] -Google / dp / B07GC4JR83? Ref_ = ast_sto_dp & th = 1)
Diesmal mit der API, ・ EIN / AUS-Betrieb des Geräts ・ Erfassung von Informationen wie EIN-AUS und Helligkeit von Glühbirnen Ich habe versucht, es in Python und Node.js auszuführen
Da das oben Genannte viele der Anwendungen abdecken kann, die als IoT-Haushaltsgeräte betrachtet werden können. ** Das Ergebnis des Gefühls der Möglichkeit der Anwendung **!
** ・ PC ** ** ・ Himbeer Pi ** ** ・ TPLink Smart Plug oder Glühbirne ** Diesmal habe ich die folgenden 3 Produkte ausprobiert HS105: Smart Plug KL110: Weiße Glühbirne KL130: Farbbirne
Testen Sie zunächst auf dem Terminal, ob Daten von TPLink abgerufen werden können.
Installieren Sie tplink-smarthome-api (Referenz)
sudo npm install -g tplink-smarthome-api
Rufen Sie mit dem folgenden Befehl eine Liste der verbundenen TPLink-Geräte ab
tplink-smarthome-api search
HS105(JP) plug IOT.SMARTPLUGSWITCH 192.168.0.101 9999 B0BE76 ‥ Smart Plug
KL110(JP) bulb IOT.SMARTBULB 192.168.0.102 9999 98DAC4 ‥ Weiße Glühbirne
KL130(JP) bulb IOT.SMARTBULB 192.168.0.103 9999 0C8063 ‥ Farbglühbirne
Sie können sehen, dass alle drei Geräte erkannt wurden
Sie können Geräteeinstellungen und OnOff mit dem folgenden Befehl abrufen
tplink-smarthome-api getSysInfo [IP-Adresse des Geräts]:9999
** ・ Beispiel für KL130 (Farbbirne) **
:
ctrl_protocols: { name: 'Linkie', version: '1.0' },
↓ Hier sind die Geräteeinstellungen
light_state: {
on_off: 1,
mode: 'normal',
hue: 0,
saturation: 0,
color_temp: 2700,
brightness: 100
},
↑ Dies ist die Geräteeinstellung
is_dimmable: 1,
is_color: 1,
:
on_off: 0 bedeutet Ausschalten, 1 bedeutet Einschalten Farbton: Farbe? (0 im Weißmodus) color_temp: Farbtemperatur (0, wenn nicht im Weißmodus) Helligkeit: Helligkeit (in%) Scheint zu sein
** ・ Beispiel für KL110 (weiße Glühbirne) **
:
ctrl_protocols: { name: 'Linkie', version: '1.0' },
↓ Hier sind die Geräteeinstellungen
light_state: {
on_off: 1,
mode: 'normal',
hue: 0,
saturation: 0,
color_temp: 2700,
brightness: 100
},
↑ Dies ist die Geräteeinstellung
is_dimmable: 1,
is_color: 0,
:
on_off: 0 bedeutet Ausschalten, 1 bedeutet Einschalten Farbton: Farbton (0 im Weißmodus) Sättigung: Sättigung color_temp: Farbtemperatur (0, wenn nicht im Weißmodus) Helligkeit: Helligkeit (in%) Es scheint, dass. Es ist fast das gleiche wie KL130, aber es ist keine Farbe, also scheint es is_color: 0 zu sein.
** ・ Beispiel für KL105 (Smart Plug) **
alias: '',
↓ Hier sind die Geräteeinstellungen
relay_state: 1,
on_time: 288,
active_mode: 'none',
feature: 'TIM',
updating: 0,
icon_hash: '',
rssi: -52,
led_off: 0,
longitude_i: 1356352,
latitude_i: 348422,
↑ Dies ist die Geräteeinstellung
hwId: '047D‥',
relay_state: 0 bedeutet Ausschalten, 1 bedeutet Einschalten on_time: Kontinuierliche Einschaltzeit rssi: WiFi-Signalstärke Es scheint, dass. Der Logitude und der Breitengrad werden ebenfalls angezeigt, aber das Rätsel vertieft sich, wenn es 5 km vom tatsächlichen Standort entfernt ist.
Oben können Sie mit dem Befehl bestätigen, dass Sie die gewünschten Informationen erhalten können! In den folgenden Kapiteln wird beschrieben, wie Sie das Programm (Node.js & Python) abrufen und bedienen.
** * Wenn Sie Node.js nicht erklären müssen, weil Sie Python verwenden, überspringen Sie dieses Kapitel und gehen Sie zu ③ **
Informationen zu Node.js finden Sie unter hier
Unter Windows wird der Pfad nicht an das globale Installationsziel von npm übergeben, und das Modul kann nicht mit Node.js geladen werden. Übergeben Sie ihn daher bitte anhand der folgenden Informationen https://qiita.com/shiftsphere/items/5610f692899796b03f99
Verwenden Sie den folgenden Befehl, um herauszufinden, wo das npm-Modul global installiert werden kann. (Aus irgendeinem Grund scheint es sich von dem Ordner zu unterscheiden, den der Befehl "npm bin -g" in Windows gefunden hat.)
npm ls -g
Bearbeiten Sie .profile mit dem folgenden Befehl.
nano /home/[Nutzername]/.profile
Fügen Sie die folgende Zeile am Ende von .profile hinzu und starten Sie den Computer neu
export NODE_PATH=[Der oben untersuchte Weg]/node_modules
Wenn der durch den folgenden Befehl angegebene Pfad angezeigt wird, ist er erfolgreich.
printenv NODE_PATH
Erstellen Sie das folgende Skript
tplink_test.js
const { Client } = require('tplink-smarthome-api');
const client = new Client();
client.getDevice({ host: '192.168.0.102' }).then(device => {
device.getSysInfo().then(console.log);
});
Wenn Sie das Skript mit dem folgenden Befehl ausführen, können Sie verschiedene Informationen auf dieselbe Weise wie mit ① abrufen.
node tplink_test.js
Das Anmelden bei Node.js hat aufgrund mangelnder JavaScript-Kenntnisse nicht funktioniert Ich habe meine Gedanken wiedererlangt und ein Skript erstellt, um mit Python zu arbeiten und mich zu protokollieren.
Python hatte Probleme, weil ich kein so höfliches Dokument wie Node.js finden konnte, aber hier und hier Ich habe den Code entschlüsselt (tplink-lb130-api / blob / master / lb130.py) und das Skript erstellt.
Oben Ich habe die folgenden 4 Klassen unter Bezugnahme auf den Code erstellt. ** TPLink_Common (): Klasse allgemeiner Funktionen für Stecker und Glühbirnen ** ** TPLink_Plug (): Nur-Plug-Funktionsklasse ** (erbt TPLink_Common ()) ** TPLink_Bulb (): Nur Glühbirnen-Funktionsklasse ** (erbt TPLink_Common ()) ** GetTPLinkData (): Eine Klasse zum Abrufen von Daten mit der obigen Klasse **
tplink.py
import socket
from struct import pack
import json
#TPLink-Datenerfassungsklasse
class GetTPLinkData():
#Methode zum Abrufen von Plug-Daten
def get_plug_data(self, ip):
#Erstellen einer Klasse für den Plug-Betrieb
plg = TPLink_Plug(ip)
#Daten abrufen und in Dikt konvertieren
rjson = plg.info()
rdict = json.loads(rjson)
return rdict
#Methode zur Erfassung von Glühbirnen-Daten
def get_bulb_data(self, ip):
#Erstellen einer Klasse zum Betreiben einer Glühbirne
blb = TPLink_Bulb(ip)
#Daten abrufen und in Dikt konvertieren
rjson = blb.info()
rdict = json.loads(rjson)
return rdict
#TPLink Glühbirne & Stecker gemeinsame Klasse
class TPLink_Common():
def __init__(self, ip, port=9999):
"""Default constructor
"""
self.__ip = ip
self.__port = port
def info(self):
cmd = '{"system":{"get_sysinfo":{}}}'
receive = self.send_command(cmd)
return receive
def send_command(self, cmd, timeout=10):
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.settimeout(timeout)
sock_tcp.connect((self.__ip, self.__port))
sock_tcp.settimeout(None)
sock_tcp.send(self.encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
decrypted = self.decrypt(data[4:])
print("Sent: ", cmd)
print("Received: ", decrypted)
return decrypted
except socket.error:
quit("Could not connect to host " + self.__ip + ":" + str(self.__port))
return None
def encrypt(self, string):
key = 171
result = pack('>I', len(string))
for i in string:
a = key ^ ord(i)
key = a
result += bytes([a])
return result
def decrypt(self, string):
key = 171
result = ""
for i in string:
a = key ^ i
key = i
result += chr(a)
return result
#TPLink-Stecker-Betriebsklasse
class TPLink_Plug(TPLink_Common):
def on(self):
cmd = '{"system":{"set_relay_state":{"state":1}}}'
receive = self.send_command(cmd)
def off(self):
cmd = '{"system":{"set_relay_state":{"state":0}}}'
receive = self.send_command(cmd)
def ledon(self):
cmd = '{"system":{"set_led_off":{"off":0}}}'
receive = self.send_command(cmd)
def ledoff(self):
cmd = '{"system":{"set_led_off":{"off":1}}}'
receive = self.send_command(cmd)
def set_countdown_on(self, delay):
cmd = '{"count_down":{"add_rule":{"enable":1,"delay":' + str(delay) +',"act":1,"name":"turn on"}}}'
receive = self.send_command(cmd)
def set_countdown_off(self, delay):
cmd = '{"count_down":{"add_rule":{"enable":1,"delay":' + str(delay) +',"act":0,"name":"turn off"}}}'
receive = self.send_command(cmd)
def delete_countdown_table(self):
cmd = '{"count_down":{"delete_all_rules":null}}'
receive = self.send_command(cmd)
def energy(self):
cmd = '{"emeter":{"get_realtime":{}}}'
receive = self.send_command(cmd)
return receive
#Betriebsklasse der TPLink-Glühbirne
class TPLink_Bulb(TPLink_Common):
def on(self):
cmd = '{"smartlife.iot.smartbulb.lightingservice":{"transition_light_state":{"on_off":1}}}'
receive = self.send_command(cmd)
def off(self):
cmd = '{"smartlife.iot.smartbulb.lightingservice":{"transition_light_state":{"on_off":0}}}'
receive = self.send_command(cmd)
def transition_light_state(self, hue: int = None, saturation: int = None, brightness: int = None,
color_temp: int = None, on_off: bool = None, transition_period: int = None,
mode: str = None, ignore_default: bool = None):
# copy all given argument name-value pairs as a dict
d = {k: v for k, v in locals().items() if k is not 'self' and v is not None}
r = {
'smartlife.iot.smartbulb.lightingservice': {
'transition_light_state': d
}
}
cmd = json.dumps(r)
receive = self.send_command(cmd)
print(receive)
def brightness(self, brightness):
self.transition_light_state(brightness=brightness)
def purple(self, brightness = None, transition_period = None):
self.transition_light_state(hue=277, saturation=86, color_temp=0, brightness=brightness, transition_period=transition_period)
def blue(self, brightness = None, transition_period = None):
self.transition_light_state(hue=240, saturation=100, color_temp=0, brightness=brightness, transition_period=transition_period)
def cyan(self, brightness = None, transition_period = None):
self.transition_light_state(hue=180, saturation=100, color_temp=0, brightness=brightness, transition_period=transition_period)
def green(self, brightness = None, transition_period = None):
self.transition_light_state(hue=120, saturation=100, color_temp=0, brightness=brightness, transition_period=transition_period)
def yellow(self, brightness = None, transition_period = None):
self.transition_light_state(hue=60, saturation=100, color_temp=0, brightness=brightness, transition_period=transition_period)
def orange(self, brightness = None, transition_period = None):
self.transition_light_state(hue=39, saturation=100, color_temp=0, brightness=brightness, transition_period=transition_period)
def red(self, brightness = None, transition_period = None):
self.transition_light_state(hue=0, saturation=100, color_temp=0, brightness=brightness, transition_period=transition_period)
def lamp_color(self, brightness = None):
self.transition_light_state(color_temp=2700, brightness=brightness)
Die obige Klasse kann wie folgt für Python-Code ausgeführt werden
** ・ Wenn Sie die Glühbirne einschalten möchten **
TPLink_Bulb(IP-Adresse der Glühbirne).on()
** ・ Wenn Sie den Stecker ausschalten möchten **
TPLink_Plug(IP-Adresse des Steckers).off()
** ・ Wenn Sie den Stecker nach 10 Sekunden einschalten möchten **
TPLink_Plug(IP-Adresse des Steckers).set_countdown_on(10)
** ・ Wenn Sie die Helligkeit der Glühbirne auf 10% erhöhen möchten **
TPLink_Bulb(IP-Adresse der Glühbirne).brightness(10)
** ・ Wenn Sie die Glühbirne rot machen möchten (nur Farbglühbirne) **
TPLink_Bulb(IP-Adresse der Glühbirne).red()
** ・ Informationen wie Ein- und Ausschalten der Glühbirne abrufen **
info = GetTPLinkData().get_plug_data(IP-Adresse des Steckers)
Mit der letzten Methode im vorherigen Kapitel habe ich ein Skript erstellt, das Informationen zu Glühbirnen und Steckern protokolliert. Die Struktur des Skripts lautet [hier](https://qiita.com/c60evaporator/items/283d0569eba58830f86e#%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B9%E3%82 Dies entspricht% AF% E3% 83% AA% E3% 83% 97% E3% 83% 88% E4% BD% 9C% E6% 88% 90). Bitte lesen Sie den Link.
[Hier](https://qiita.com/c60evaporator/items/283d0569eba58830f86e#%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3 Wie beim Artikel% 83% AB) haben wir die folgenden zwei Arten von Einstellungsdateien zur einfacheren Verwaltung erstellt. -DeviceList.csv: Beschreiben Sie die erforderlichen Informationen für jeden Sensor
DeviceList.csv
ApplianceName,ApplianceType,IP,Retry
TPLink_KL130_ColorBulb_1,TPLink_ColorBulb,192.168.0.103,2
TPLink_KL110_WhiteBulb_1,TPLink_WhiteBulb,192.168.0.102,2
TPLink_HS105_Plug_1,TPLink_Plug,192.168.0.101,2
Die Bedeutung der Spalten ist wie folgt ApplianceName: Verwalten Sie Gerätenamen und identifizieren Sie mehrere Geräte desselben Typs ApplianceType: Gerätetyp. TPLink_ColorBulb: Farbbirne (KL130 usw.) TPLink_WhiteBulb: Weiße Glühbirne (KL110 usw.) TPLink_Plug: Smart Plug (HS105 usw.) IP: IP-Adresse des Geräts Wiederholen: Maximale Anzahl von Neuausführungen Details (Anzahl der erneuten Ausführungen, wenn die Erfassung fehlschlägt, Details [hier](https://qiita.com/c60evaporator/items/283d0569eba58830f86e#%E4%B8%8D%E5%85%B7%E5] % 90% 881peripheral% E3% 81% AE% E5% 88% 9D% E6% 9C% 9F% E5% 8C% 96% E6% 99% 82% E3% 81% AB% E3% 82% A8% E3% 83 % A9% E3% 83% BC% E3% 81% 8C% E5% 87% BA% E3% 82% 8B))
-Config.ini: Geben Sie das CSV- und Protokollausgabeverzeichnis an
config.ini [Path] CSVOutput = /share/Data/Appliance LogOutput = /share/Log/Appliance Wenn beide in einem von samba erstellten freigegebenen Ordner ausgegeben werden, ist es bequem, von außerhalb des Raspberry Pi darauf zuzugreifen.
appliance_data_logger.py
from tplink import GetTPLinkData
import logging
from datetime import datetime, timedelta
import os
import csv
import configparser
import pandas as pd
#Globale Variablen
global masterdate
######TPLink-Datenerfassung######
def getdata_tplink(appliance):
#Maximale Zufriedenheit, wenn kein Datenwert verfügbar ist.Wiederholen Wiederholen Sie den Scan
for i in range(appliance.Retry):
try:
#Beim Einstecken
if appliance.ApplianceType == 'TPLink_Plug':
applianceValue = GetTPLinkData().get_plug_data(appliance.IP)
#Wenn es eine Glühbirne ist
elif appliance.ApplianceType == 'TPLink_ColorBulb' or appliance.ApplianceType == 'TPLink_WhiteBulb':
applianceValue = GetTPLinkData().get_bulb_data(appliance.IP)
else:
applianceValue = None
#Protokollausgabe, wenn ein Fehler auftritt
except:
logging.warning(f'retry to get data [loop{str(i)}, date{str(masterdate)}, appliance{appliance.ApplianceName}]')
applianceValue = None
continue
else:
break
#Wenn der Wert erhalten werden kann, speichern Sie die POST-Daten in dict
if applianceValue is not None:
#Beim Einstecken
if appliance.ApplianceType == 'TPLink_Plug':
data = {
'ApplianceName': appliance.ApplianceName,
'Date_Master': str(masterdate),
'Date': str(datetime.today()),
'IsOn': str(applianceValue['system']['get_sysinfo']['relay_state']),
'OnTime': str(applianceValue['system']['get_sysinfo']['on_time'])
}
#Wenn es eine Glühbirne ist
else:
data = {
'ApplianceName': appliance.ApplianceName,
'Date_Master': str(masterdate),
'Date': str(datetime.today()),
'IsOn': str(applianceValue['system']['get_sysinfo']['light_state']['on_off']),
'Color': str(applianceValue['system']['get_sysinfo']['light_state']['hue']),
'ColorTemp': str(applianceValue['system']['get_sysinfo']['light_state']['color_temp']),
'Brightness': str(applianceValue['system']['get_sysinfo']['light_state']['brightness'])
}
return data
#Wenn es nicht erhalten werden konnte, protokollieren Sie die Ausgabe
else:
logging.error(f'cannot get data [loop{str(appliance.Retry)}, date{str(masterdate)}, appliance{appliance.ApplianceName}]')
return None
######CSV-Ausgabe von Daten######
def output_csv(data, csvpath):
appliancename = data['ApplianceName']
monthstr = masterdate.strftime('%Y%m')
#Name des Ausgabeordnerordners
outdir = f'{csvpath}/{appliancename}/{masterdate.year}'
#Wenn der Ausgabezielordner nicht vorhanden ist, erstellen Sie einen neuen
os.makedirs(outdir, exist_ok=True)
#Pfad der Ausgabedatei
outpath = f'{outdir}/{appliancename}_{monthstr}.csv'
#Erstellen Sie eine neue Ausgabedatei, wenn diese nicht vorhanden ist
if not os.path.exists(outpath):
with open(outpath, 'w', newline="") as f:
writer = csv.DictWriter(f, data.keys())
writer.writeheader()
writer.writerow(data)
#Fügen Sie eine Zeile hinzu, wenn die Ausgabedatei vorhanden ist
else:
with open(outpath, 'a', newline="") as f:
writer = csv.DictWriter(f, data.keys())
writer.writerow(data)
######Maine######
if __name__ == '__main__':
#Startzeit bekommen
startdate = datetime.today()
#Runden Sie die Startzeit in Minuten ab
masterdate = startdate.replace(second=0, microsecond=0)
if startdate.second >= 30:
masterdate += timedelta(minutes=1)
#Konfigurationsdatei und Geräteliste lesen
cfg = configparser.ConfigParser()
cfg.read('./config.ini', encoding='utf-8')
df_appliancelist = pd.read_csv('./ApplianceList.csv')
#Gesamtzahl der Sensoren und erfolgreiche Datenerfassung
appliance_num = len(df_appliancelist)
success_num = 0
#Protokollinitialisierung
logname = f"/appliancelog_{str(masterdate.strftime('%y%m%d'))}.log"
logging.basicConfig(filename=cfg['Path']['LogOutput'] + logname, level=logging.INFO)
#Diktat für das Speichern aller erfassten Daten
all_values_dict = None
######Datenerfassung für jedes Gerät######
for appliance in df_appliancelist.itertuples():
#Stellen Sie sicher, dass der Appliance-Typ TPLinke ist
if appliance.ApplianceType in ['TPLink_Plug','TPLink_ColorBulb','TPLink_WhiteBulb']:
data = getdata_tplink(appliance)
#Andere als die oben genannten
else:
data = None
#Wenn Daten vorhanden sind, fügen Sie sie zu Dict hinzu, um alle Daten zu speichern und CSV auszugeben
if data is not None:
#all_values_Erstellen Sie ein neues Wörterbuch, wenn dict Keine ist
if all_values_dict is None:
all_values_dict = {data['ApplianceName']: data}
#all_values_Zum vorhandenen Wörterbuch hinzufügen, wenn dict nicht None ist
else:
all_values_dict[data['ApplianceName']] = data
#CSV-Ausgabe
output_csv(data, cfg['Path']['CSVOutput'])
#Erfolgszahl plus
success_num+=1
#Protokollausgabe des Verarbeitungsende
logging.info(f'[masterdate{str(masterdate)} startdate{str(startdate)} enddate{str(datetime.today())} success{str(success_num)}/{str(appliance_num)}]')
Wenn Sie die oben genannten Schritte ausführen, werden die erfassten Daten in CSV mit dem Gerätenamen sowie dem Namen von Datum und Uhrzeit in dem in der Einstellungsdatei "CSVOutput" angegebenen Ordner ausgegeben.
Damit ist die Informationserfassung abgeschlossen.
Es läuft 24 Stunden am Tag auf RaspberrypPi und Python hat mehr Freiheit als IFTTT, sodass Sie verschiedene Ideen verkörpern können. ・ Kombiniert mit einem menschlichen Sensor, um beim Betreten einer Person Strom einzuschalten ・ Schalten Sie das Licht aus, wenn 30 Minuten oder länger keine Personen anwesend sind ・ Schaltet die Helligkeit der Glühbirne je nach Person automatisch um Und so weiter.
Ich habe einige Dinge, die ich machen möchte, also werde ich wieder darüber schreiben, wenn die Produktion abgeschlossen ist.
Recommended Posts