Page 4 of 13
Re: TP-Link smart plug HS100/HS110
Posted: Thursday 01 March 2018 15:11
by cdk222
Hi Mike
I am receiving similar errors to MnM001 and have been spinning my wheels on it for a couple of days now:
Traceback (most recent call last):
File "./tplink-smartplug-HS110.py", line 60, in <module>
jsonData = json.loads(result)
File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
return _default_decoder.decode(s)
File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python2.7/json/decoder.py", line 382, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded
Code: Select all
#!/usr/bin/env python
#
# TP-Link Wi-Fi Smart Plug Protocol Client
# For use with TP-Link HS110: energy monitor
#
# Gets current power (W) and cumulative energy (kWh)
# and sends to Domoticz
import socket
import argparse
import json
import urllib
import urllib2
# ip, port, and command for HS110
ip = '10.1.1.5'
port = 9999
cmd = '{"emeter":{"get_realtime":{}}}'
# Domoticz command stub and IDx of HS110
baseURL = 'http://<10.1.1.5:8080>/json.htm?type=command¶m=udevice&nvalue=0'
HSIdx = 2
# Encryption and Decryption of TP-Link Smart Home Protocol
# XOR Autokey Cipher with starting key = 171
def encrypt(string):
key = 171
result = "\0\0\0\0"
for i in string:
a = key ^ ord(i)
key = a
result += chr(a)
return result
def decrypt(string):
key = 171
result = ""
for i in string:
a = key ^ ord(i)
key = ord(i)
result += chr(a)
return result
def domoticzrequest (url):
request = urllib2.Request(url)
# request.add_header("Authorization", "Basic %s" % base64string)
response = urllib2.urlopen(request)
return None;
# Send command and receive reply
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect((ip, port))
sock_tcp.send(encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
# print "Sent: ", cmd
result = decrypt(data[4:])
jsonData = json.loads(result)
# print "Received: "
# print json.dumps(jsonData, indent=4, sort_keys=True)
power = jsonData['emeter']['get_realtime']['power']
total = jsonData['emeter']['get_realtime']['total'] * 1000
# print power, total
except socket.error:
quit("Cound not connect to host " + ip + ":" + str(port))
# Send data to Domoticz
try:
url = baseURL + "&idx=%s&svalue=%s;%s" % (HSIdx, power, total)
domoticzrequest(url)
except urllib2.URLError, e:
print e.code
Looking at
https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s i did notice a slight variation in the syntax they use for the following:
Electricity (instant and counter)
/json.htm?type=command¶m=udevice&idx=IDX&nvalue=0&svalue=POWER;ENERGY
........however others including yourself have this working with your code so im not sure where I am going wrong. I have messed around with the IP & port but no luck. I can turn the plug on\off using the another HSxxx script (tplink-smartplug.py).
Please Help!!!
Re: TP-Link smart plug HS100/HS110
Posted: Thursday 01 March 2018 17:32
by MikeF
@cdk222,
First of all, make sure that ip = '10.1.1.5' is the ip address of your HS110; you've got the same ip address in baseURL - this should be your Domoticz ip. Also, remove the <> here, and try again. Then see below, if this doesn't work.
@MnM001,
I've come across a bash script for HS100 / HS110 here:
https://github.com/ggeorgovassilis/linuxscripts.
On my HS110 I get:
Code: Select all
./HS100.sh 192.168.0.84 9999 on
found 0 associations
found 1 connections:
1: flags=82<CONNECTED,PREFERRED>
outif en0
src 192.168.0.10 port 63787
dst 192.168.0.84 port 9999
rank info not available
TCP aux info available
Connection to 192.168.0.84 port 9999 [tcp/distinct] succeeded!
This bash script has some interesting dependencies and diagnostics, which might have a bearing.
If this (and your 'python tplink-smartplug.py -t 192.168.0.151 -c time') doesn't work, then I'm wondering if TP-Link have changed the encryption / decryption of these devices?
If so, I don't know what to suggest (I was following this website:
https://www.softscheck.com/en/reverse-e ... ink-hs110/).
Re: TP-Link smart plug HS100/HS110
Posted: Saturday 03 March 2018 10:36
by cdk222
Thanks Mike
I had tried numerous combinations of IP and unfortunately I left the incorrect one in the code I posted.
Have spend the day playing around with the code and found numerous updates that needed to be made for the newer version of Python. In particular the urllib commands and the HS110 'power' and 'total' syntax.
The below worked in the end for me although I need to update the value's sent to domoticz......next on the list
Thanks again
Code: Select all
#!/usr/bin/python3
#
#################################################################################################
#################################################################################################
#
# TP-Link Wi-Fi Smart Plug Protocol Energy Monitoring Client
# For use with TP-Link HS-110
#
#
# Additional Information:
#
# https://www.domoticz.com/forum/viewtopic.php?f=56&t=13290
# https://www.softscheck.com/en/reverse-engineering-tp-link-hs110/
#
# Complete URL String to Send to Domoticz
# http://DOMSERVER_IP:8080/json.htm?type=command¶m=udevice&nvalue=0&idx=IDX&svalue=POWER;TOTAL
#
#################################################################################################
#################################################################################################
import socket
import argparse
import json
import urllib
import urllib.request
version = 0.1
# Check if IP is valid
def validIP(ip):
try:
socket.inet_pton(socket.AF_INET, ip)
except socket.error:
parser.error("Invalid IP Address.")
return ip
# Predefined Smart Plug Commands
# For a full list of commands, consult tplink_commands.txt
commands = {'info' : '{"system":{"get_sysinfo":{}}}',
'on' : '{"system":{"set_relay_state":{"state":1}}}',
'off' : '{"system":{"set_relay_state":{"state":0}}}',
'cloudinfo': '{"cnCloud":{"get_info":{}}}',
'wlanscan' : '{"netif":{"get_scaninfo":{"refresh":0}}}',
'time' : '{"time":{"get_time":{}}}',
'schedule' : '{"schedule":{"get_rules":{}}}',
'countdown': '{"count_down":{"get_rules":{}}}',
'antitheft': '{"anti_theft":{"get_rules":{}}}',
'reboot' : '{"system":{"reboot":{"delay":1}}}',
'reset' : '{"system":{"reset":{"delay":1}}}',
'energy' : '{"emeter":{"get_realtime":{}}}'
}
# Encryption and Decryption of TP-Link Smart Home Protocol
# XOR Autokey Cipher with starting key = 171
def encrypt(string):
key = 171
result = b"\0\0\0"+ chr(len(string)).encode('latin-1')
for i in string.encode('latin-1'):
a = key ^ i
key = a
result += chr(a).encode('latin-1')
return result
def decrypt(string):
key = 171
result = ""
for i in string:
a = key ^ i
key = i
result += chr(a)
return result
# Parse commandline arguments
parser = argparse.ArgumentParser(description="TP-Link Wi-Fi Smart Plug Client v" + str(version))
parser.add_argument("-t", "--target", metavar="<ip>", required=True, help="Target IP Address", type=validIP)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-c", "--command", metavar="<command>", help="Preset command to send. Choices are: "+", ".join(commands), choices=commands)
group.add_argument("-j", "--json", metavar="<JSON string>", help="Full JSON string of command to send")
args = parser.parse_args()
# Domoticz command stub and IDx of HS110
baseURL = 'http://<DOMOTICZ IP>:8080/json.htm?type=command¶m=udevice&nvalue=0'
HSIdx = <IDX from Domoticz>
# Set target IP, port and command to send
ip = args.target
port = 9999
if args.command is None:
cmd = args.json
else:
cmd = commands[args.command]
# Send command and receive reply
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect((ip, port))
sock_tcp.send(encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
cmdresult = decrypt(data[4:])
jsonData = json.loads(cmdresult)
power = jsonData['emeter']['get_realtime']['power_mw']
total = jsonData['emeter']['get_realtime']['total_wh'] * 1000
url = baseURL + "&idx=%s&svalue=%s;%s" % (HSIdx, power, total)
domreq = urllib.request.Request(url)
# Troubleshooting Print Commands
# print (json.dumps(jsonData, indent=4,sort_keys=True))
# print(power,total)
# print(url)
# print("Sent: ", cmd)
# print("Received: ", decrypt(data[4:]))
except socket.error:
quit("Cound not connect to host " + ip + ":" + str(port))
try:
urllib.request.urlopen(domreq)
except Exception as e:
print(str(e))
Re: TP-Link smart plug HS100/HS110
Posted: Saturday 03 March 2018 16:26
by MikeF
@cdk222,
Glad you seem to have got this working - maybe the difference in our experiences is because I am using Python 2.7?
Re: TP-Link smart plug HS100/HS110
Posted: Sunday 04 March 2018 5:09
by cdk222
@Mike
Thats exactly what it was. Thanks for the original code
Re: TP-Link smart plug HS100/HS110
Posted: Tuesday 06 March 2018 19:54
by cazz
Just here to say thanks MikeF for the script that you post in page 1
Have a HS100 and was curious if I can use that too read the Watt for me.
Re: TP-Link smart plug HS100/HS110
Posted: Wednesday 07 March 2018 12:20
by MikeF
The HS100 is just a wifi smart plug - the HS110 includes energy monitoring.
Re: TP-Link smart plug HS100/HS110
Posted: Wednesday 07 March 2018 15:59
by cazz
Sorry I mean HS110

Re: TP-Link smart plug HS100/HS110
Posted: Wednesday 14 March 2018 4:35
by kawa
For those using python3 you can use the following python code:
To switch on/off (tplink-smartplug.py)
Code: Select all
#!/usr/bin/env python3
#
# TP-Link Wi-Fi Smart Plug Protocol Client
# For use with TP-Link HS-100 or HS-110
#
# by Lubomir Stroetmann
# Copyright 2016 softScheck GmbH
#
# modified by Kawa
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
import socket
import argparse
version = 0.5
# Check if IP is valid
def validIP(ip):
try:
socket.inet_pton(socket.AF_INET, ip)
except socket.error:
parser.error("Invalid IP Address.")
return ip
# Predefined Smart Plug Commands
# For a full list of commands, consult tplink_commands.txt
commands = {'info' : '{"system":{"get_sysinfo":{}}}',
'on' : '{"system":{"set_relay_state":{"state":1}}}',
'off' : '{"system":{"set_relay_state":{"state":0}}}',
'cloudinfo': '{"cnCloud":{"get_info":{}}}',
'wlanscan' : '{"netif":{"get_scaninfo":{"refresh":0}}}',
'time' : '{"time":{"get_time":{}}}',
'schedule' : '{"schedule":{"get_rules":{}}}',
'countdown': '{"count_down":{"get_rules":{}}}',
'antitheft': '{"anti_theft":{"get_rules":{}}}',
'reboot' : '{"system":{"reboot":{"delay":1}}}',
'reset' : '{"system":{"reset":{"delay":1}}}'
}
# Encryption and Decryption of TP-Link Smart Home Protocol
# XOR Autokey Cipher with starting key = 171
def encrypt(string):
key = 171
result = b"\0\0\0"+ chr(len(string)).encode('utf-8')
for i in string.encode('utf-8'):
a = key ^ i
key = a
result += chr(a).encode('utf-8')
return result
def decrypt(string):
key = 171
result = ""
for i in string:
a = key ^ i
key = i
result += chr(a)
return result
# Parse commandline arguments
parser = argparse.ArgumentParser(description="TP-Link Wi-Fi Smart Plug Client v" + str(version))
parser.add_argument("-t", "--target", metavar="<ip>", required=True, help="Target IP Address", type=validIP)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-c", "--command", metavar="<command>", help="Preset command to send. Choices are: "+", ".join(commands), choices=commands)
group.add_argument("-j", "--json", metavar="<JSON string>", help="Full JSON string of command to send")
args = parser.parse_args()
# Set target IP, port and command to send
ip = args.target
port = 9999
if args.command is None:
cmd = args.json
else:
cmd = commands[args.command]
# Send command and receive reply
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect((ip, port))
sock_tcp.send(encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
# print ("Sent: ", cmd)
# print ("Received: ", decrypt(data[4:]))
except socket.error:
quit("Cound not connect to host " + ip + ":" + str(port))
Calling the script by adding the following on/off actions to the virtual switch (my tplink plug has ip 192.168.1.32):
Code: Select all
script://tplink-smartplug.py -t 192.168.1.32 -c on
Code: Select all
script://tplink-smartplug.py -t 192.168.1.32 -c off
I have the following script to get the status (tplink-status.py)
Code: Select all
#!/usr/bin/env python3
#
# TP-Link Wi-Fi Smart Plug Protocol Client
# For use with TP-Link HS100
#
# modified by Kawa
#
# Gets current switch status
# and sends to Domoticz
import socket
import argparse
import json
import urllib.request, urllib.parse, urllib.error
import urllib.request, urllib.error, urllib.parse
# Check if IP is valid
def validIP(ip):
try:
socket.inet_pton(socket.AF_INET, ip)
except socket.error:
parser.error("Invalid IP Address.")
return ip
parser = argparse.ArgumentParser(description="TP-Link Wi-Fi Smart Plug Client")
parser.add_argument("-t", "--target", metavar="<ip>", required=True, help="Target IP Address", type=validIP)
parser.add_argument("-i", "--idx", metavar="<idx>", help="Which Domoticz IDX")
parser.add_argument("-d", "--domoticz", metavar="<Domoticz IP>", help="Full IP address with port number for Domoticz")
args = parser.parse_args()
# ip, port, and command for HS100
ip = args.target
port = 9999
cmd = '{"system":{"get_sysinfo":{}}}'
idx = args.idx
domoticzIP = args.domoticz
# Domoticz command stub and IDx of HS100
baseURL = 'http://' + domoticzIP + '/json.htm?type=command¶m=udevice&idx=' + str(idx) + '&nvalue='
# Encryption and Decryption of TP-Link Smart Home Protocol
# XOR Autokey Cipher with starting key = 171
def encrypt(string):
key = 171
result = b"\0\0\0"+ chr(len(string)).encode('latin-1')
for i in string.encode('latin-1'):
a = key ^ i
key = a
result += chr(a).encode('latin-1')
return result
def decrypt(string):
key = 171
result = ""
for i in string:
a = key ^ i
key = i
result += chr(a)
return result
def domoticzrequest (url):
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)
result = response.read()
return result;
def getcurrentstate():
url = 'http://' + domoticzIP + '/json.htm?type=devices&rid=' + str(idx)
response = domoticzrequest(url)
jsonData = json.loads(response)
status = jsonData['result'][0]['Status']
lampState = 0
if status == "On":
lampState = 1
return lampState;
# Send command and receive reply
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect((ip, port))
sock_tcp.send(encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
result = decrypt(data[4:])
jsonData = json.loads(result)
relay_state = jsonData['system']['get_sysinfo']['relay_state']
except socket.error:
quit("Cound not connect to host " + ip + ":" + str(port))
# Send data to Domoticz
try:
currentState = getcurrentstate()
if currentState != relay_state:
url = baseURL + str(relay_state)
domoticzrequest(url)
except urllib.error.URLError as e:
print((e.code))
I have the following line in crontab:
(the plug has ip 192.168.1.32 and the virtual switch has idx 5 on domoticz running on 192.168.1.50:8080
Code: Select all
* * * * * /config/scripts/tplink-status.py -t 192.168.1.32 -i 5 -d 192.168.1.50:8080 > /var/log/tplink.log
Re: TP-Link smart plug HS100/HS110
Posted: Friday 22 June 2018 17:09
by Mdieli
I just received 2 HS110 plugs and I am trying to setup the Domoticz "link".
I want to be able to switch them ofcource. But more important, I want them also to report power consumption with a short (15 - 60 seconds) interval.
I found (at least) 2 different scripts to enable switching (tplink-smartplug.py and hs100.sh) and 1 script to retrieve power consumption and send it to domoticz (tplink-status.py)
With the hs100.sh script, i have no problem to switch it on/off.
However, I am having trouble to get the python scripts to work.
Problem 1
When excuting:
Code: Select all
./tplink-smartplug.py -t 192.168.1.165 -j '{"emeter":{"get_realtime":{}}}'
I receive NO response at all. (I'm 100% sure about the IP: I tried it with another IP, and then I receive the error that it is the wrong IP)
Code: Select all
Sent: {"emeter":{"get_realtime":{}}}
Received:
The same happens when I try to switch on/off
Code: Select all
./tplink-smartplug.py -t 192.168.1.165 -c on
Code: Select all
Sent: {"system":{"set_relay_state":{"state":1}}}
Received:
Problem 2
When executing:
Code: Select all
./tplink-status.py -t 192.168.1.165 -i 1891 -d 192.168.1.150:8080
I receive the following error:
Code: Select all
Traceback (most recent call last):
File "./tplink-status.py", line 97, in <module>
currentState = getcurrentstate()
File "./tplink-status.py", line 73, in getcurrentstate
jsonData = json.loads(response)
File "/usr/lib/python3.5/json/__init__.py", line 312, in loads
s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'
The IPs, port and IDX are 100% correct btw.
Anyone who can point me in the right direction?
Re: TP-Link smart plug HS100/HS110
Posted: Saturday 23 June 2018 13:30
by MikeF
I've not been using my HS110 for a while, but I've just reinstalled it (as a Switch - Electric (Instant + Counter)) in Domoticz, and I'm running this python script (which I previously published in this thread - 3 October 2016):
- Spoiler: show
Code: Select all
#!/usr/bin/env python
#
# TP-Link Wi-Fi Smart Plug Protocol Client
# For use with TP-Link HS110: energy monitor
#
# Gets current power (W) and cumulative energy (kWh)
# and sends to Domoticz
import socket
import argparse
import json
import urllib
import urllib2
# ip, port, and command for HS110
ip = '192.168.0.xx'
port = 9999
cmd = '{"emeter":{"get_realtime":{}}}'
# Domoticz command stub and IDx of HS110
baseURL = 'http://192.168.0.xx:8080/json.htm?type=command¶m=udevice&nvalue=0'
HSIdx = 302
# Encryption and Decryption of TP-Link Smart Home Protocol
# XOR Autokey Cipher with starting key = 171
def encrypt(string):
key = 171
result = "\0\0\0\0"
for i in string:
a = key ^ ord(i)
key = a
result += chr(a)
return result
def decrypt(string):
key = 171
result = ""
for i in string:
a = key ^ ord(i)
key = ord(i)
result += chr(a)
return result
def domoticzrequest (url):
request = urllib2.Request(url)
# request.add_header("Authorization", "Basic %s" % base64string)
response = urllib2.urlopen(request)
return None;
# Send command and receive reply
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect((ip, port))
sock_tcp.send(encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
# print "Sent: ", cmd
result = decrypt(data[4:])
jsonData = json.loads(result)
# print "Received: "
# print json.dumps(jsonData, indent=4, sort_keys=True)
power = jsonData['emeter']['get_realtime']['power']
total = jsonData['emeter']['get_realtime']['total'] * 1000
# print power, total
except socket.error:
quit("Cound not connect to host " + ip + ":" + str(port))
# Send data to Domoticz
try:
url = baseURL + "&idx=%s&svalue=%s;%s" % (HSIdx, power, total)
domoticzrequest(url)
except urllib2.URLError, e:
print e.code
and it's working OK:
Note that I'm using python 2.7 (on a RPi 2), and there may be differences with python 3.x (e.g., around urllib / urllib2); also, I'm not using authorisation in Domoticz. You could try uncommenting some of the print statements, as a debugging aid.
Mike
Re: TP-Link smart plug HS100/HS110
Posted: Sunday 24 June 2018 8:48
by Mdieli
MikeF wrote: ↑Saturday 23 June 2018 13:30
...
Thanks for the script, it is a lot like the one I allready had.
After some investigation, I found that the post @ softcheck.com was eddited and a commend was added:
UPDATE 19.06.2018:
TP-Link has updated their firmware. If you install this firmware upgrade, tplink-smartplug.py does not work anymore.
https://www.softscheck.com/en/reverse-e ... ink-hs110/
I'm note sure if the 0 (zero) response I receive from the switch is an indication that I have the latest firmware. Also not sure how to check this if updates are pushed by the app automatically.
According the app, the current firmware version I have is 1.4.3
Re: TP-Link smart plug HS100/HS110
Posted: Sunday 24 June 2018 9:03
by Mdieli
I found that updates are done via the app indeed.
I checked, and the app says there is 1 update availabl for the switch. So not the latest firmware yet I guess.
Does anyone have the same firmware as I and have it working? (1.4.3)
Re: TP-Link smart plug HS100/HS110
Posted: Sunday 24 June 2018 10:06
by MikeF
I wasn't aware of this... I don't (and won't!) use Kasa with my HS110.
I am wary of applying 'latest versions' of apps / firmware, in case they remove /disrupt features I was previously using - e.g., iOS 11.4 removes support for Airport Express.
... and Gizmocuz has just announced new Domoticz stable, 4.9700!

Re: TP-Link smart plug HS100/HS110
Posted: Sunday 24 June 2018 13:51
by Mdieli
In the meantime, I found out there was/is a tool for the PC to upgrade the firmware in the past. I tried to up/downgrade to a previous one but no result.
Fortunate, I saw an post on the git page from Home Assistant, there was one person that also had troubles but found out it was an little API change. Heb changed the python script from HA a bit and has it working again. Unfortunate, I'm not a coder.

Re: TP-Link smart plug HS100/HS110
Posted: Sunday 24 June 2018 18:56
by MikeF
Can you post that script? I'll have a look.
Re: TP-Link smart plug HS100/HS110
Posted: Sunday 24 June 2018 20:57
by Mdieli
This is the code that should work with HA:
Code: Select all
"""
Support for TPLink HS100/HS110/HS200 smart switch.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/switch.tplink/
"""
import logging
import time
import voluptuous as vol
from homeassistant.components.switch import (
SwitchDevice, PLATFORM_SCHEMA, ATTR_CURRENT_POWER_W, ATTR_TODAY_ENERGY_KWH)
from homeassistant.const import (CONF_HOST, CONF_NAME, ATTR_VOLTAGE)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['pyHS100==0.3.2']
_LOGGER = logging.getLogger(__name__)
ATTR_TOTAL_ENERGY_KWH = 'total_energy_kwh'
ATTR_CURRENT_A = 'current_a'
CONF_LEDS = 'enable_leds'
DEFAULT_NAME = 'TP-Link Switch'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_LEDS): cv.boolean,
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the TPLink switch platform."""
from pyHS100 import SmartPlug
host = config.get(CONF_HOST)
name = config.get(CONF_NAME)
leds_on = config.get(CONF_LEDS)
add_devices([SmartPlugSwitch(SmartPlug(host), name, leds_on)], True)
class SmartPlugSwitch(SwitchDevice):
"""Representation of a TPLink Smart Plug switch."""
def __init__(self, smartplug, name, leds_on):
"""Initialize the switch."""
self.smartplug = smartplug
self._name = name
if leds_on is not None:
self.smartplug.led = leds_on
self._state = None
self._available = True
# Set up emeter cache
self._emeter_params = {}
@property
def name(self):
"""Return the name of the Smart Plug, if any."""
return self._name
@property
def available(self) -> bool:
"""Return if switch is available."""
return self._available
@property
def is_on(self):
"""Return true if switch is on."""
return self._state
def turn_on(self, **kwargs):
"""Turn the switch on."""
self.smartplug.turn_on()
def turn_off(self):
"""Turn the switch off."""
self.smartplug.turn_off()
@property
def device_state_attributes(self):
"""Return the state attributes of the device."""
return self._emeter_params
def update(self):
"""Update the TP-Link switch's state."""
from pyHS100 import SmartDeviceException
try:
self._available = True
self._state = self.smartplug.state == \
self.smartplug.SWITCH_STATE_ON
if self._name is None:
self._name = self.smartplug.alias
if self.smartplug.has_emeter:
emeter_readings = self.smartplug.get_emeter_realtime()
for value in emeter_readings :
try :
name, unit = value.split("_",1)
div = 1000
except ValueError:
name = value.split("_",1)[0]
div = 1
if name == "power":
self._emeter_params[ATTR_CURRENT_POWER_W] \
= "%.1f W" % (float(emeter_readings[value])/div)
if name == "total":
self._emeter_params[ATTR_TODAY_ENERGY_KWH] \
= "%.2f kW" % (float(emeter_readings[value])/div)
if name == "voltage":
self._emeter_params[ATTR_VOLTAGE] \
= "%.2f V" % (float(emeter_readings[value])/div)
if name == "current":
self._emeter_params[ATTR_CURRENT_A] \
= "%.1f A" % (float(emeter_readings[value])/div)
try:
emeter_statics = self.smartplug.get_emeter_daily()
self._emeter_params[ATTR_TODAY_ENERGY_KWH] \
= "%.2f kW" % (float(emeter_statics[int(time.strftime("%e"))]/1000))
except KeyError:
# Device returned no daily history
pass
except (SmartDeviceException, OSError) as ex:
_LOGGER.warning("Could not read state for %s: %s", self.name, ex)
self._available = False
This is the file in HA. I'm not sure if this fix has been implemented there yet:
https://github.com/home-assistant/home- ... /tplink.py
Re: TP-Link smart plug HS100/HS110
Posted: Wednesday 11 July 2018 19:00
by Olfer
Hi guys,
"UPDATE 04.07.2018:
We updated our tool. It now supports TP-Link HS100, HS105 and HS110 with the latest firmware. Hostnames instead of IP addresses are also supported and the script can now be imported as a Python module. A big thank you to the persons who opened issues and pull requests on GitHub."
https://www.softscheck.com/en/reverse-e ... ink-hs110/
Cheers!
Update from my side: version 0.2 (latest) seems to work for me! You can download it from GitHub from. Softscheck, see link above.
Re: TP-Link smart plug HS100/HS110
Posted: Sunday 15 July 2018 22:22
by Hofland
I received my HS110 today and did a firmware update.
I can sucessfully read the data with the Softscheck tool.
Has anyone created a script based on the latest Softscheck tool to send the HS110 energy data to Domoticz?
Re: TP-Link smart plug HS100/HS110
Posted: Tuesday 17 July 2018 16:42
by Olfer
Hi,
You'll have to...
* replace the encrypt and decrypt functions with new ones
* add the 'from struct import pack' line
* alter the json query to... ']['power_mw'] / 1000
* alter the json query to...']['total_wh']
Sry I'm not at home.. This description is all I can deliver for now. Also I'm just getting integer values for power. If someone could help.... Would be great! Thanks in advance!