
I purchased this Presto Dehydro many years ago and have used it a few times. It works, and I thought I would be okay with the single temperature, but it was ultimately just disappointing. Foods tasted a little on the overcooked side rather than something, well, good. I mainly use it to dehydrate home grown chilies, and for that you want a temperature around 115-120F. You can pay more than double the price to get the Presto Dehydro with a touch panel, but if you have a Wemo Smart Plug hanging around, and a willingness to play with some Python, then you can make some custom temperatures on your own. I also purchased a set of the fruit roll sheets and the non-stick mesh sheets. I always put a fruit roll sheet on the bottom layer to catch any drippings and make cleanup easier, and the non-stick mesh sheets to hold food that may fall through as it gets smaller with moisture loss.
I’m going to rant a little, but there’s a point to it: On the surface I love the concept of Wemo Smart Plug’s, and I own 8 of them, but the app has been sketchy with plugs as they get older. Take for example, the plug will be on, the lamp will be powered on through it, I can turn it on/off via voice with Alexa, but if I do it with Google by voice, sometimes Google says it can’t find it, so I open the Wemo app, and sure enough that Wemo device doesn’t display. I look at my network settings on my router and see the IP assigned to the Wemo device. I can see the device show up in my Windows Network, and I can ping it. WHAT GIVES WEMO??? While I was going through this moment of frustration trying to get this to work, I had a big pile of peppers I was going to dehydrate, and I wondered if I could program a Wemo plug to turn on for a minute and turn off for a minute to get a lower temperature in the dehydrator. That answer was not without a lot of painstaking manual work in their app, hoping the plug you want to program doesn’t spontaneously disappear in the middle of setting up a nightmare’s worth of rules because there is no rule for “auto-on” after a period of time, just a rule for “auto-off” after a period of time. Then I thought, what if I could programmatically control the Wemo by script, and if I could control it programmatically, why couldn’t I just create a custom timer at an even more optimal level to get the right temperature, so I did that.
Except I didn’t just do that, I found one of the scarce resources available online where somebody else has already done most of the leg work to talk to the Wemo plugs, and I tacked on a bit at the end to create the customized timed toggles.
This isn’t a Python tutorial, so if you need help with that to get this to work, there are plenty of other resources out there to get you on your way.
First you need to find the Wemo plug’s IP address. On Windows you can press the Win Key and type “View network computers” and press the result in Control Panel. You should see “Other Devices” and then the name of the Wemo plug you want. Click on that device and it will open a page in your browser like “http://192.168.0.112:49153/pluginpres.html”. That will get you the IP address you need, in my case it’s “192.168.0.112” you can ignore the rest. I have no idea what that page is even for, especially since it’s a big 404, but it easily gets you the IP address of the right device.
Copy the code below into a file named wemo.py Make sure you have Python3 installed, and update the variable “wemoIp” to the IP address you found for your Wemo. Run “python wemo.py” to start the toggling. Install any missing dependencies it complains about until you see “toggling on” and then you know it’s running. Double check your dehydrator (or anything else you want to intermittently toggle on and off with the smart plug) to make sure it is turning on and off from the script.
Let it do its thing for about 5 minutes, then measure the temperature either by sticking an instant-read thermometer through the vents in the top of the dehydrator, or by using a laser infrared thermometer. If it’s too low, or high you can adjust the “onSeconds” or “offSeconds” variable to compensate. In my case I set it for 120 seconds on and 45 seconds off and I achieved 112F, and after roughly 3 hours I had perfectly dehydrated peppers.
#!/usr/bin/python
# Credit for most of this goes to https://gist.github.com/tbma2014us/b7c524f9b9c21151e64e5eca9a519649 and https://gist.github.com/pruppert/af7d38cb7b7ca75584ef
# rewritten for python 2/3 and requests
from __future__ import print_function
import argparse
import logging
import re
import sys
import socket
import requests
import threading
wemoIp = '192.168.0.112'
onSeconds = 120.0
offSeconds = 45.0
options = None
LOG_FORMAT = '%(asctime)s %(filename)s:%(lineno)s[%(process)d]: %(levelname)s: %(message)s'
class ArgsParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
kwargs.setdefault(
'description',
'Controls WeMo switches')
argparse.ArgumentParser.__init__(self, *args, **kwargs)
self.formatter_class = argparse.RawTextHelpFormatter
self.options = None
self.epilog = '''
For example:
{0} 192.168.1.2 on
{0} 192.168.1.2 off
{0} wemo1.mydomain.com on -v
{0} wemo1.mydomain.com toggle -nq
'''.format(__file__)
self.add_argument('address', help="IP address or hostname of the WeMo switch")
self.add_argument('command', choices=('on', 'off', 'toggle', 'status'))
self.add_argument('-nq', '--not-quiet', dest='quiet', action='store_false', default=True, help='Be not quiet')
self.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Be verbose')
def error(self, message):
sys.stderr.write('ERROR: %s\n\n' % message)
self.print_help()
sys.exit(2)
def parse_args(self, *args, **kwargs):
_options = argparse.ArgumentParser.parse_args(self, *args, **kwargs)
self.options = _options
return _options
class WeMo:
OFF_STATE = '0'
ON_STATES = ['1', '8']
ip = None
ports = [49153, 49152, 49154, 49151, 49155]
def __init__(self, switch_ip):
if not switch_ip.replace('.', "").isdigit():
switch_ip = socket.gethostbyname(switch_ip)
try:
socket.inet_aton(switch_ip)
except socket.error:
raise Exception("InvalidIPAddress")
self.ip = switch_ip
def toggle(self):
status = self.status()
if status in self.ON_STATES:
return self.off()
elif status == self.OFF_STATE:
return self.on()
else:
raise Exception("UnexpectedStatusResponse")
def on(self):
self._send('Set', 'BinaryState', 1)
return self.status()
def off(self):
self._send('Set', 'BinaryState', 0)
return self.status()
def status(self):
result = self._send('Get', 'BinaryState')
self._status_to_text(result)
return result
def name(self):
return self._send('Get', 'FriendlyName')
def signal(self):
return self._send('Get', 'SignalStrength')
def _status_to_text(self, status):
if status in self.ON_STATES:
logging.info('WeMo is now on')
elif status in self.OFF_STATE:
logging.info('WeMo is now off')
else:
logging.info('WeMo is in unknown state')
return status
@staticmethod
def _get_header_xml(method, obj):
method = method + obj
return '"urn:Belkin:service:basicevent:1#%s"' % method
@staticmethod
def _get_body_xml(method, obj, value=0):
method = method + obj
return '<u:%s xmlns:u="urn:Belkin:service:basicevent:1"><%s>%s</%s></u:%s>' % (
method, obj, value, obj, method
)
def _send(self, method, obj, value=None):
body_xml = self._get_body_xml(method, obj, value)
header_xml = self._get_header_xml(method, obj)
for port in self.ports:
result = self._try_send(self.ip, port, body_xml, header_xml, obj)
if result is not None:
self.ports = [port]
return result
raise Exception("TimeoutOnAllPorts")
def _try_send(self, _ip, port, _body, header, data):
try:
logging.info("Connecting to %s:%s" % (_ip, port))
headers = {'Content-type': 'text/xml; charset="utf-8"',
'SOAPACTION': header}
request_body = '<?xml version="1.0" encoding="utf-8"?>'
request_body += '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" ' \
's:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
request_body += '<s:Body>%s</s:Body></s:Envelope>' % _body
result = requests.get(
'http://%s:%s/upnp/control/basicevent1' % (_ip, port),
data=request_body,
headers=headers,
timeout=3
)
return self._extract(result.text, data)
except Exception as _:
print(str(_))
return None
@staticmethod
def _extract(response, name):
exp = '<%s>(.*?)<\\/%s>' % (name, name)
g = re.search(exp, response)
if g:
return g.group(1)
return response
def output(message):
print(message)
def main(address, command):
# my_parser = ArgsParser()
# global options
# options = my_parser.parse_args(args)
# logging.basicConfig(stream=sys.stdout, level=logging.INFO, format=LOG_FORMAT)
switch = WeMo(address)
if command == 'on':
output(
switch.on()
)
elif command == 'off':
output(
switch.off()
)
elif command == 'toggle':
output(
switch.toggle()
)
else:
output(
switch.status()
)
def wemoOn():
main(wemoIp, 'on')
print('toggling on')
threading.Timer(onSeconds, wemoOff).start()
def wemoOff():
main(wemoIp, 'off')
print('toggling off')
threading.Timer(offSeconds, wemoOn).start()
wemoOn()