0

I have cobbled together a script which runs as a standalone python file. It successfully connects to the HS110 smart plug from Kasa/TPLINK and posts the power in Watts to my webserver. This all works.

However, as part of a cron job, it doesn't and I can't seem to understand why. I imagine it's something glaringly obvious.

import socket
import json
from struct import pack
import requests

version = 0.4


# 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}}}',
            'ledoff'   : '{"system":{"set_led_off":{"off":1}}}',
            'ledon'    : '{"system":{"set_led_off":{"off":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 = pack(">I", len(string))
    for i in string:
        a = key ^ ord(i)
        key = a
        result += bytes([a])
    return result

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



# Set target IP, port and command to send
ip = '192.168.1.20'
port = 9999
abc = 'energy'

cmd = commands[abc]

# Send command and receive reply
try:
    sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock_tcp.settimeout(int(1000))
    sock_tcp.connect((ip, port))
    sock_tcp.settimeout(None)
    sock_tcp.send(encrypt(cmd))
    data = sock_tcp.recv(2048)
    sock_tcp.close()

    decrypted = decrypt(data[4:])
     
    decrypted_dict = json.loads(decrypted)
    livingroompower = decrypted_dict["emeter"]["get_realtime"]["power_mw"]
    print (livingroompower)

except socket.error:
    quit(f"Could not connect to host {ip}:{port}")



userdata = {"livingroompower": livingroompower}
resp = requests.post('web address here', params=userdata)

The script is butchered from various other scripts, but like I said, stand alone, it works... No filepath related issues as far as I can see.

Very much appreciate any help here!

1 Answer 1

1

What command do you set in your crontab file? Is the script intended to run once and done or constantly post power readings?

As you mention, crons can fail because of path issues. Not only for the script but also for python if that is how you are running the script. For example:

@reboot /usr/bin/python3 /home/pi/example.py

You may wish to save the output of your script to an easily accesible file so errors can be analyzed there. >> appends to a file or creates the file if it doesn't exist while > overwrites the file if it exists or creates it if it doesn't exist. For example:

@reboot /usr/bin/python3 /home/pi/example.py >> /tmp/cron.log

Your problem could be related to your cron job running before the network is established. You may be able to test this by checking the output from your script as described above. If this is the case the inelegant solution would be to add a delay to your cron,

@reboot sleep 300 && /usr/bin/python3 /home/pi/example.py

But this won't always work. You can use a script to check for the connection and delay until it is formed, i.e. ping a DNS server until it responds then run your script.

My preference would be to use a service instead of a cron job. This post explains configuring a service to depend on the network. https://unix.stackexchange.com/a/126146/408086

also, https://www.raspberrypi.org/documentation/linux/usage/systemd.md

1
  • 1
    Unfortunately I have less than 15 reputation so my up vote won't be publicly displayed for now. Very much appreciate your detailed response. In my tired and exhausted state last night, I totally overlooked the filepath to python!! Implementing this fixed the cron job. However, the additional pointer to set this up as a service is something I see is much more beneficial and more robust. Mar 4, 2021 at 9:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.