TP-Link smart plug HS100/HS110

Others (MiLight, Hue, Toon etc...)

Moderator: leecollings

crazynight
Posts: 13
Joined: Saturday 07 October 2017 18:05
Target OS: -
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by crazynight »

pi@raspberrypi:~/domoticz/scripts/python/hs110 $ python tplink_hs110.py -c energy
Traceback (most recent call last):
File "tplink_hs110.py", line 238, in <module>
hs.read_hs110()
File "tplink_hs110.py", line 224, in read_hs110
self.send_json(received_data)
File "tplink_hs110.py", line 155, in send_json
voltage = round(float(json_data['emeter']['get_realtime']['voltage_mv']) / 1000,2)
KeyError: 'voltage_mv
Domoticz v3.8153 - Rpi
RFLink r48- Arduino Mega Chinese 433 RX TX
2x bye bye Standby Switches
TP-Link HS100
1x DHT11 & 1x ds18B20 connected directly yo the RPi
Nodemcu flashed with ESPEasy
1x ds18B20 connected to the Nodemcu
crazynight
Posts: 13
Joined: Saturday 07 October 2017 18:05
Target OS: -
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by crazynight »

the log file looks like this:

2018-12-10 21:06:59,584:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:07:09,785:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:07:24,508:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:08:59,398:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:33:06,028:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:33:15,944:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:34:55,214:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-10 21:39:34,335:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:24:39,104:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:24:43,742:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:24:47,615:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:24:51,219:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:29:19,305:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:33:39,302:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 20:37:34,762:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 21:01:49,402:__main__:INFO:hs110-1 version 0.5 has started...
2018-12-11 22:11:04,519:__main__:INFO:hs110-1 version 0.5 has started...
Domoticz v3.8153 - Rpi
RFLink r48- Arduino Mega Chinese 433 RX TX
2x bye bye Standby Switches
TP-Link HS100
1x DHT11 & 1x ds18B20 connected directly yo the RPi
Nodemcu flashed with ESPEasy
1x ds18B20 connected to the Nodemcu
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

@crazynight, if you go back a few posts and/or look at github you will see that HS110s have different energy commands depending on whether they return i.e. milliVolts or Volts. Another member has successfully corrected the energy part by changing these values in code as per my instructions here viewtopic.php?f=56&t=13290&start=100#p193180. That should fix KeyError: 'voltage_mv'

If it's still not working after that, you can turn debugging on to get more info in the log. Change debug_level="INFO" to debug_level="DEBUG".
page3
Posts: 4
Joined: Saturday 13 July 2013 8:54
Target OS: -
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by page3 »

Hi ajay100

Great script - thanks.

I have two (version 1) plugs using the original scripts to switch on/off and also to gather usage statistics.

I bought a new plug, which is a version 2 so the original scripts didn't work. Initially I used the plugin available from this thread, but it would occasionally throw a segmentation fault so I thought I'd try aj100's script instead.

I had/have two issues, but it's running fine now.

Issue 1:
It would keep exiting with what I though was the KeyError problem but that turned out to be a red herring. If I printed out what was being sent to Domoticz and pasted it in to a browser it works fine. From the script it did not. Looking at the old script I determined it might be the headers are not being sent correctly, so I took that code from the original script and that solved it.

Place this code before the class definition:

Code: Select all

def domoticzrequest (url):
  request = urllib2.Request(url)
  request.add_header("Authorization", "Basic %s" % base64string)
  response = urllib2.urlopen(request)
  return None;
Then replace calls to urllib2 with this function instead, eg:

Code: Select all

# urllib2.urlopen(full_url)
          domoticzrequest(full_url)
Remember to define base64string in the user setting section:

Code: Select all

base64string = 'ZGF2aXNhOmFydGkyYW4='
Issue 2:
Overnight the script bombed out:

Code: Select all

pi@domoticz:~ $ sudo systemctl status -l tplink_hs110
● tplink_hs110.service - Python script monitors TP-Link HS110 smart switch
   Loaded: loaded (/lib/systemd/system/tplink_hs110.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Sun 2018-12-23 23:55:29 GMT; 9h ago
  Process: 11348 ExecStart=/usr/bin/python /home/pi/domoticz/scripts/tplink-loft.py -c energy (code=exited, status=1/FAILURE)
 Main PID: 11348 (code=exited, status=1/FAILURE)

Dec 23 23:55:28 domoticz python[11348]:   File "/home/pi/domoticz/scripts/tplink-loft.py", line 246, in <module>
Dec 23 23:55:29 domoticz python[11348]:     hs.read_hs110()
Dec 23 23:55:29 domoticz python[11348]:   File "/home/pi/domoticz/scripts/tplink-loft.py", line 232, in read_hs110
Dec 23 23:55:29 domoticz python[11348]:     self.send_json(received_data)
Dec 23 23:55:29 domoticz python[11348]:   File "/home/pi/domoticz/scripts/tplink-loft.py", line 193, in send_json
Dec 23 23:55:29 domoticz python[11348]:     out = time.strftime("%Y-%m-%d %H:%M:%S") + "," + str(kwhr) + "\n"
Dec 23 23:55:29 domoticz python[11348]: NameError: global name 'kwhr' is not defined
Dec 23 23:55:29 domoticz systemd[1]: tplink_hs110.service: Main process exited, code=exited, status=1/FAILURE
Dec 23 23:55:29 domoticz systemd[1]: tplink_hs110.service: Unit entered failed state.
Dec 23 23:55:29 domoticz systemd[1]: tplink_hs110.service: Failed with result 'exit-code'.
Taking a look at line 192 (in my version of the code) I could see:

Code: Select all

out = time.strftime("%Y-%m-%d %H:%M:%S") + "," + str(kwhr) + "\n"
kwhr is not defined anywhere else, so I commented this and the following line out. This "solved" the issue as I didn't need the daily output log.

I hope this information may be of use to others :)
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

Hopefully you all can help me out with this one. After reading all eight pages of this forum post, I have gotten a lot wiser, but have not yet found the solution to my problem with the HS110. This forum has helped me before, so I wish to thank you in advance for all your great work and help.

When using the ajay10000 https://github.com/ajay10000/TP-Link-HS ... k_hs110.py script, I want to get energy readings/counters in Domoticz but I keep getting errors in the log file:

2019-05-20 21:30:49.848 Error: EventSystem: Failed to execute python event script "TPlinkSwitch"
2019-05-20 21:30:49.848 Error: EventSystem: File "<string>", line 214
2019-05-20 21:30:49.848 Error: EventSystem: print "Could not connect to host " + self.ip + ":" + str(self.port) + " " + str(self.error_count) + " times" #debug
2019-05-20 21:30:49.848 Error: EventSystem: ^
2019-05-20 21:30:49.848 Error: EventSystem: SyntaxError: invalid syntax

These are the steps (from scratch) which I have taken:
1. Sucessfully used the tplink_smartplug.py script https://github.com/softScheck/tplink-sm ... artplug.py
2. This gives all the output as would be expected (switches the HS110 on and off, gives energy readings, etc.)
3. Already had a Dummy hardware (Idx 3)
4. Created four new vitual sensors: Watts (idx 8), kWh (idx 9), Volt (idx 10), Current (idx 11), Switch (idx 12)
5. Put the ajay10000 script in Domoticz Events through the GUI (Setup --> More Options --> Events --> Python --> New)
6. Changed the ip-address to that of the Rpi and to that of the HS110
7. Checked the Python version = 2.7.13

But it seems I am missing a step.

If needed, I can make screenshots of the hardware and devices. I am at a total loss. Maybe I forgot a step, but I can't see which one it is.

The entire code I am using now, is:

Code: Select all

#!/usr/bin/env python2
#
# 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 Andrew P (ajay10000), 2018
#
# 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.
#
# Example from command line:
# python tplink_hs110.py -c energy
# Sent:      {"emeter":{"get_realtime":{}}}
# Received:  {"emeter":{"get_realtime":{"voltage_mv":242630,"current_ma":19,"power_mw":1223,"total_wh":184,"err_code":0}}}

import socket, argparse, json, urllib, urllib2, logging, os, time, datetime
from struct import pack

# Begin user editable variables
version = 0.5
logger_name = "hs110-1"  #used for log file names, messages, etc
debug_level="INFO"  # debug options DEBUG, INFO, WARNING, ERROR, CRITICAL
delay_time = 15 #update time in seconds
domain="http://192.168.1.14:8080/"
base_url = domain + "json.htm?type=command&param=udevice&nvalue=0"
monitor_list = ["voltage","current","power","usage"]
domoticz_idx = [10,11,8,9]
hs110_ip = "192.168.1.74"
text_logging = True
track_state = True
hs110_switch_idx = 12
datafile_columns = "Time,Voltage,Current,Power (W),Usage (kWHr)"
dailyfile_columns = "Date-Time,Usage (kWHr)"
# End user editable variables

log_path = os.path.dirname(os.path.realpath(__file__)) 
log_level = getattr(logging, debug_level.upper(), 10)
logging.basicConfig(filename=log_path + "/" + logger_name + ".log", level=log_level, format="%(asctime)s:%(name)s:%(levelname)s:%(message)s")
logger = logging.getLogger(__name__)
dailyfile = log_path + "/" + logger_name + "_daily.csv"
datafile = log_path + "/" + logger_name + "_data.csv"
logger.info("{} version {} has started...".format(logger_name, version))

class HS110:
  def __init__(self):
    self.error_count = 0
    if text_logging:
      self.next_daily_time = datetime.datetime.combine(datetime.date.today(),datetime.time(23,55,0))
      # Set up headers for log and daily files
      if not os.path.isfile(datafile):
        self.write_file(datafile,"w",datafile_columns + "\n")
      if not os.path.isfile(dailyfile):
        self.write_file(dailyfile,"w",dailyfile_columns + "\n")
      
    # 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}}}',
        'led_on'   : '{"system":{"set_led_off":{"off":0}}}',
        'led_off'  : '{"system":{"set_led_off":{"off":1}}}',
        'state'    : '{"system":{"get_sysinfo":{}}}',
        '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":{}}}'
    }
   
    # Parse commandline arguments
    parser = argparse.ArgumentParser(description="TP-Link Wi-Fi Smart Plug Client v" + str(version))
    parser.add_argument("-t", "--target", metavar="<hostname>", help="Target hostname or IP address", type=self.validHostname)
    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")
    self.args = parser.parse_args()

    # Set target IP, port and command to send
    self.port = 9999
    if self.args.target is None:
      self.ip = hs110_ip
    else:
      self.ip = self.args.target
    if self.args.command is None:
      self.cmd = self.args.json
    else:
      self.cmd = commands[self.args.command]
    
  # Check for valid hostname
  def validHostname(self, hostname):
    try:
      socket.gethostbyname(hostname)
    except socket.error:
      parser.error("Invalid hostname.")
    return hostname

  # Encryption and Decryption of TP-Link Smart Home Protocol
  # XOR Autokey Cipher with starting key = 171
  def encrypt(self, string):
    key = 171
    result = pack(">I", len(string))
    for i in string:
      a = key ^ ord(i)
      key = a
      result += chr(a)
    return result

  def decrypt(self, string):
    key = 171
    result = ""
    for i in string:
      a = key ^ ord(i)
      key = ord(i)
      result += chr(a)
    return result

  # Generic file writing function
  def write_file(self,file_name,write_type,text):
    try:
      fil = open(file_name, write_type)
      fil.write(text)
    except IOError as e:
      logger.error("I/O error({}): {}".format(e.errno, e.strerror))
    else:
      fil.close()

  # Send json to app such as domoticz if requested in command (using "energy" or "state")
  def send_json(self,received_data):
    json_data = json.loads(received_data)
    try:
      if self.read_state:
        state = json_data['system']['get_sysinfo']['relay_state']
        full_url = domain + "json.htm?type=command&param=udevice&idx={}&nvalue={}".format(hs110_switch_idx,state)
        logger.debug("URL: {}".format(full_url))
        # Send the json string
        urllib2.urlopen(full_url)
      else:
        voltage = round(float(json_data['emeter']['get_realtime']['voltage_mv']) / 1000,2)
        current = round(float(json_data['emeter']['get_realtime']['current_ma']) / 1000,2)
        power = round(float(json_data['emeter']['get_realtime']['power_mw']) / 1000,2)
        usage = round(float(json_data['emeter']['get_realtime']['total_wh']) / 1000,3)
    
        for i in range(0,len(domoticz_idx)): # range is 0 based
          if i < len(domoticz_idx) - 1:
            logger.debug("IDX: {}, Item: {}, Value: {}".format(domoticz_idx[i],monitor_list[i],eval(monitor_list[i])))
            full_url = base_url + "&idx={}&svalue={}".format(domoticz_idx[i],eval(monitor_list[i]))
          else:
            # virtual sensor with sensor type Electric (Instant+Counter)
            logger.debug("IDX: {}, Items: {}, Values: {};{}".format(domoticz_idx[i],"Power (W), Usage (kWhr)",power,usage))
            full_url = base_url + "&idx={}&svalue={};{}".format(domoticz_idx[i],power,usage * 1000)
          logger.debug("URL: {}".format(full_url))
          # Send the json string
          urllib2.urlopen(full_url)
        
    except urllib2.HTTPError as e:
      # Error checking to prevent crashing on bad requests
      logger.error("HTTP error({}): {}".format(e.errno, e.strerror))
    except urllib2.URLError as e:
      logger.error("URL error({}): {}".format(e.errno, e.strerror))
    
    # write out the text file logs if required.  Don't log state.  
    if text_logging and (not self.read_state):      
      out = time.strftime("%Y-%m-%d %H:%M:%S") + "," + str(voltage) + "," + str(current) + "," + str(power) + "," + str(usage) + "\n"
      self.write_file(datafile, "a", out)
      
      if datetime.datetime.now() > self.next_daily_time:
        self.next_daily_time = datetime.datetime.combine(datetime.date.today() + datetime.timedelta(days=1),datetime.time(23,55,0))
        out = time.strftime("%Y-%m-%d %H:%M:%S") + "," + str(kwhr) + "\n"
        self.write_file(dailyfile, "a", out)

  # Send command to smart switch and receive reply
  # read_state is a special case for updating Domoticz with state
  def read_hs110(self, read_state = False):
    data = ""
    try:
      sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      sock_tcp.connect((self.ip, self.port))
      if read_state:
        self.read_state = True
        hs_cmd = '{"system":{"get_sysinfo":{}}}'
      else:
        self.read_state = False
        hs_cmd = self.cmd
      logger.debug("Command: {}".format(hs_cmd))
      sock_tcp.send(self.encrypt(hs_cmd))
      data = sock_tcp.recv(2048)
      sock_tcp.close()
      received_data = self.decrypt(data[4:])
      # Successful read, reset error_count
      self.error_count = 0

    except socket.error:
      self.error_count += 1
      logger.error("Could not connect to host {}:{} {} times".format(self.ip,str(self.port),self.error_count))
      # Allow for a few connection errors.
      if self.error_count > 10:
        print "Could not connect to host " + self.ip + ":" + str(self.port) + " " + str(self.error_count) + " times"  #debug
        raise SystemExit(0)
      else:
        return   
    
    # json should be sent if command includes "energy" or "state"
    if "energy" in str(self.args) or "state" in str(self.args):
      logger.debug("Sent:     {}".format(hs_cmd))
      logger.debug("Received: {}".format(received_data))
      if received_data is not None:
        self.send_json(received_data)
    else:
      # Direct command, so print to console and exit
      print "Sent:     ", hs_cmd
      print "Received: ", received_data
      # write out the text file logs if required  
      if text_logging:      
        out = time.strftime("%Y-%m-%d %H:%M:%S") + ",Command: " + hs_cmd + ",,\n"
        self.write_file(datafile, "a", out)
      raise SystemExit(0)

if __name__ == "__main__":
  hs = HS110()
  while True:
    hs.read_hs110()
    # check if state should be updated in domoticz
    if track_state:
      hs.read_hs110(track_state)
    time.sleep(delay_time)
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

@DaanV, can you change debug_level="INFO" to debug_level="DEBUG" and show the recent entries for log hs110-1.log from /home/pi/domoticz/scripts/python (or your equivalent folder)?

I seem to remember that the Python3 version script was required, as that is what I am using. My Domoticz version is V4.9700.

Cheers - Andrew
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

ajay100 wrote: Tuesday 21 May 2019 14:28 @DaanV, can you change debug_level="INFO" to debug_level="DEBUG" and show the recent entries for log hs110-1.log from /home/pi/domoticz/scripts/python (or your equivalent folder)?

I seem to remember that the Python3 version script was required, as that is what I am using. My Domoticz version is V4.9700.

Cheers - Andrew
Thanks for your reply. I have changed the debug_level into DEBUG, but there is no log file created. I take it the log file should be created in the same folder as the original script? In all the other folders, I'm not seeing a log file either.
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

Yes, the log file should be created in the same folder, but it is probably not getting that far. Can you try running it from the command line to capture the error/info in the console?

Code: Select all

python2 tplink_hs110.py -c info
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

ajay100 wrote: Wednesday 22 May 2019 9:01 Yes, the log file should be created in the same folder, but it is probably not getting that far. Can you try running it from the command line to capture the error/info in the console?

Code: Select all

python2 tplink_hs110.py -c info
Yeah, I figured as much as the script not getting that far.

This is the output I am getting

Sent: {"system":{"get_sysinfo":{}}}
Received: {"system":{"get_sysinfo":{"sw_ver":"1.5.4 Build 180815 Rel.121440","hw_ver":"2.0","type":"IOT.SMARTPLUGSWITCH","model":"HS110(EU)","mac":"D8:0D:17:3E:71:0B","dev_name":"Smart Wi-Fi Plug With Energy Monitoring","alias":"smart plug","relay_state":1,"on_time":140781,"active_mode":"none","feature":"TIM:ENE","updating":0,"icon_hash":"","rssi":-47,"led_off":0,"longitude_i":42398,"latitude_i":520860,"hwId":"044A516EE63C875F9458DA25C2CCC5A0","fwId":"00000000000000000000000000000000","deviceId":"80060C3658261AE94D9F0AD99575DEF41AFB863E","oemId":"1998A14DAA86E4E001FD7CAF42868B5E","next_action":{"type":-1},"err_code":0}}}
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

Thanks @DaanV, I think that result shows that there is a problem with the format of the command being sent to the HS110 from the script. It is OK with the direct -c info command, but failing with the -c energy command. I have tested the python2 script you are using with my settings and it is updating Domoticz and writing logs to the same folder.

Can you please comment out the line around 214 with a #:

Code: Select all

# print "Could not connect to host " + self.ip + ":" + str(self.port) + " " + str(self.error_count) + " times"  #debug
then run this directly from the command line:

Code: Select all

python2 tplink_hs110.py -c energy
so that we can then see what comes up in the console and/or logs?

Cheers - Andrew
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

@ajay100

Thanks for the new idea. I have commented out line 214 and ran the script again from the command line. An interesting thing happens now. In the terminal nothing happens:
Screenshot 2019-05-30 at 09.29.12.png
Screenshot 2019-05-30 at 09.29.12.png (12.15 KiB) Viewed 2838 times
I also had my MacOS Finder open and noticed in the Domoticz folder, there suddenly were two csv files with the tplink_hs110 name. I then went back to the Domoticz interface in my browser and the meters are now working.

Then I tried to insert the code into the Domoticz Events, but then the log is showing this error:
Screenshot 2019-05-30 at 09.36.47.png
Screenshot 2019-05-30 at 09.36.47.png (61.41 KiB) Viewed 2838 times
I've let it run for about a minute and this is the log file:
hs110-1.log
(12.55 KiB) Downloaded 114 times
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

@DaanV, that's great it is working! If you comment out the print statements in lines 227 and 228 it might also work from Domoticz Events. These lines are for echoing to the console when using the script in direct mode (such as you did with -c info).

In Python3 the print syntax changed to i.e.

Code: Select all

print("Sent: ", hs_cmd)
so I'm a bit surprised by that error, but if commenting out the print statements works, you could try changing to this syntax for the print statements (and uncomment them) to see if that fixes it completely. You might find as I did that Domoticz is using Python3, whereas the system default is Python2.

Cheers - Andrew
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

@ajay100
I tried out commenting out pine 227 and 228. Now I get this error:
Screenshot 2019-05-30 at 11.19.36.png
Screenshot 2019-05-30 at 11.19.36.png (27.18 KiB) Viewed 2833 times
When I started this whole adventure, I have tried replacing parts of the code with the Python3 code, like you suggested, as I figured there might be a conflict between Python versions. I have just added your suggestion to the code, to see what happens. I've replaced:

Code: Select all

      print "Sent:     ", hs_cmd
      print "Received: ", received_data
with

Code: Select all

        print("Sent: ", hs_cmd)
        print("Received: ", hs_cmd)
the error then becomes:
Screenshot 2019-05-30 at 11.24.00.png
Screenshot 2019-05-30 at 11.24.00.png (74.71 KiB) Viewed 2833 times
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

OK, that does suggest that the Python3 script is required for your Domoticz Events option.

The first error complains about urllib2, which is not used in Python3. It would be useful to see what error/s you get if you try the Python3 version of the script.

The second error is usually easy to fix. Python is strict about indents as it uses these to detect which bits of code belong together, like braces may do in other programming languages (my paraphrasing!) The space or tab size of the indent doesn't matter, as long as it is consistent. From around line 235, that section should look something like this:

Code: Select all

    else:
      # Direct command, so print to console and exit
      print("Sent:     ", hs_cmd)
      print("Received: ", received_data)
      # write out the text file logs if required  
      if text_logging:      
        out = time.strftime("%Y-%m-%d %H:%M:%S") + ",Command: " + hs_cmd + ",,\n"
        self.write_file(datafile, "a", out)
      raise SystemExit(0)
However, I think this path will continue with errors until you convert the code to Python3.
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

@ajay100

I have changed that section into the one you suggested. The error now is:
Screenshot 2019-05-30 at 12.28.48.png
Screenshot 2019-05-30 at 12.28.48.png (28.45 KiB) Viewed 2832 times
What do you suggest to do now? How do I convert the code into Python 3?

I have found a Python 3 code here:
https://github.com/ajay10000/TP-Link-HS110

Changed the 'user editable variables' and activated the script. It already starts with an error at the beginning of the script:
Screenshot 2019-05-30 at 12.43.27.png
Screenshot 2019-05-30 at 12.43.27.png (28.69 KiB) Viewed 2832 times
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

The error 'NameError: name '__file__' is not defined' looks like it might be due to a difference between MAC and my RPi Linux operating systems. I searched for this error with reference to a MAC. According to this post: https://www.blog.pythonlibrary.org/2013 ... ng-script/ try changing line 49 to:

Code: Select all

log_path = os.path.abspath(os.path.dirname(sys.argv[0]))
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

Hmm. That's weird. I am running Domoticz on an RPi with Raspbian Debian 9 (Stretch)

Changing the line into the new code, just gave a new error on the same line.

What would be the explanation for the Python2 script running from the command line and even sending the data to the dummy meters I created, whilst giving errors when I ran it from the Domoticz Events?
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

Sorry! That's my mistake - when I read
I also had my MacOS Finder open
I jumped to conclusions.

I believe Python2 is the default on RPi Stretch (it is on mine). That is why the Python2 version successfully runs from the command line and updates Domoticz.

I got myself tied in knots trying to change the RPi OS default to Python3, so gave up. However, you can call a Python3 script from the command line using

Code: Select all

python3 scriptname
which is what I do. I also use this method in systemd scripts to automatically start Python3 scripts on boot. I'm being a bit pig-headed and trying to make all my scripts run in Python3! However I don't want to start an argument about the merits of 2 vs 3 because I'm not an experienced Python programmer.

I do know from experience that these cul-de-sacs are frustrating, but if you can bear with me, try running the Python3 version script from the command line (if you haven't already) with DEBUG on and report back any errors from the command line or log file.

Code: Select all

 python3 tplink_hs110.py -c info
which should give you the HS110 information in the console. Then try

Code: Select all

 python3 tplink_hs110.py -c energy
which should show nothing in the console, but the log files should update.
DaanV
Posts: 14
Joined: Thursday 02 May 2019 11:14
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: TP-Link smart plug HS100/HS110

Post by DaanV »

No worries, I could have been more clear about the systeem I'm running Domoticz on.

And I'll bear with you for as long as you are still enjoying helping me out. I am grateful there are people like you, helping out people like me.

The Python3 script is running smoothly from the command line. The info command gives the output one would expect. The energy option is indeed doing nothing in command line, but updating the log file and printing the data to the dummy meters in Domoticz.

As a way of a short cut to solve this, can we make the script run from the systemd automatically? As they are now running from the command line, I should take it that it works from the systemd? I just care about it running, I am not persistent on using it from the Events scripts in Domoticz.

If I would follow this guide, would it work, you think?
https://www.raspberrypi-spy.co.uk/2015/ ... g-systemd/
ajay100
Posts: 72
Joined: Monday 07 August 2017 15:01
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: Victoria, Australia
Contact:

Re: TP-Link smart plug HS100/HS110

Post by ajay100 »

That looks like a good tutorial. Here is my systemd script:

Code: Select all


[Unit]
Description=TP-Link HS110 smart switch service
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python3 /home/pi/domoticz/scripts/python/tplink_hs110.py -c energy

[Install]

WantedBy=multi-user.target
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 1 guest