Skip to content

Commit f51cb5f

Browse files
committed
move idle timer stop to system shutdown function instead of in turn off function to resolve issues related to multiple plugs, #254
1 parent c532078 commit f51cb5f

File tree

2 files changed

+38
-61
lines changed

2 files changed

+38
-61
lines changed

octoprint_tplinksmartplug/__init__.py

Lines changed: 37 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
from __future__ import absolute_import
33

44
import octoprint.plugin
5-
from octoprint.access.permissions import Permissions, ADMIN_GROUP, USER_GROUP
6-
from octoprint.events import eventManager, Events
5+
from octoprint.access.permissions import Permissions, ADMIN_GROUP
6+
from octoprint.events import Events
77
from octoprint.util import RepeatedTimer
88
from flask_babel import gettext
99
import socket
@@ -15,7 +15,6 @@
1515
import threading
1616
import time
1717
import sqlite3
18-
import decimal
1918
from uptime import uptime
2019
from datetime import datetime
2120
from struct import unpack
@@ -221,6 +220,7 @@ def on_settings_save(self, data):
221220
if old_polling_value != new_polling_value or old_polling_timer != new_polling_timer:
222221
if self.poll_status is not None:
223222
self.poll_status.cancel()
223+
self.poll_status = None
224224

225225
if new_polling_value:
226226
self.poll_status = RepeatedTimer(int(self._settings.get(["pollingInterval"])) * 60, self.check_statuses)
@@ -299,11 +299,17 @@ def on_settings_migrate(self, target, current=None):
299299

300300
def get_assets(self):
301301
return dict(
302-
js=["js/jquery-ui.min.js", "js/knockout-sortable.1.2.0.js", "js/fontawesome-iconpicker.js",
302+
js=["js/jquery-ui.min.js",
303+
"js/knockout-sortable.1.2.0.js",
304+
"js/fontawesome-iconpicker.js",
303305
"js/ko.iconpicker.js",
304-
"js/tplinksmartplug.js", "js/knockout-bootstrap.min.js", "js/ko.observableDictionary.js",
306+
"js/tplinksmartplug.js",
307+
"js/knockout-bootstrap.min.js",
308+
"js/ko.observableDictionary.js",
305309
"js/plotly-latest.min.js"],
306-
css=["css/font-awesome.min.css", "css/font-awesome-v4-shims.min.css", "css/fontawesome-iconpicker.css",
310+
css=["css/font-awesome.min.css",
311+
"css/font-awesome-v4-shims.min.css",
312+
"css/fontawesome-iconpicker.css",
307313
"css/tplinksmartplug.css"]
308314
)
309315

@@ -330,7 +336,7 @@ def on_print_progress(self, storage, path, progress):
330336
_print_progress_timer.start()
331337
self._plugin_manager.send_plugin_message(self._identifier, dict(updatePlot=True))
332338

333-
if self.powerOffWhenIdle == True and not (self._skipIdleTimer == True):
339+
if self.powerOffWhenIdle is True and not (self._skipIdleTimer is True):
334340
self._tplinksmartplug_logger.debug("Resetting idle timer during print progress (%s)..." % progress)
335341
self._waitForHeaters = False
336342
self._reset_idle_timer()
@@ -348,19 +354,15 @@ def turn_on(self, plugip):
348354
plug_num = -1
349355
if plug["useCountdownRules"] and int(plug["countdownOnDelay"]) > 0:
350356
self.sendCommand(json.loads('{"count_down":{"delete_all_rules":null}}'), plug_ip, plug_num)
351-
chk = self.lookup(self.sendCommand(json.loads(
352-
'{"count_down":{"add_rule":{"enable":1,"delay":%s,"act":1,"name":"turn on"}}}' % plug[
353-
"countdownOnDelay"]), plug_ip, plug_num), *["count_down", "add_rule", "err_code"])
357+
chk = self.lookup(self.sendCommand(json.loads('{"count_down":{"add_rule":{"enable":1,"delay":%s,"act":1,"name":"turn on"}}}' % plug["countdownOnDelay"]), plug_ip, plug_num), *["count_down", "add_rule", "err_code"])
354358
if chk == 0:
355359
self._countdown_active = True
356-
c = threading.Timer(int(plug["countdownOnDelay"]) + 3, self._plugin_manager.send_plugin_message,
357-
[self._identifier, dict(check_status=True, ip=plugip)])
360+
c = threading.Timer(int(plug["countdownOnDelay"]) + 3, self._plugin_manager.send_plugin_message, [self._identifier, dict(check_status=True, ip=plugip)])
358361
c.daemon = True
359362
c.start()
360363
else:
361364
turn_on_cmnd = dict(system=dict(set_relay_state=dict(state=1)))
362-
chk = self.lookup(self.sendCommand(turn_on_cmnd, plug_ip, plug_num),
363-
*["system", "set_relay_state", "err_code"])
365+
chk = self.lookup(self.sendCommand(turn_on_cmnd, plug_ip, plug_num), *["system", "set_relay_state", "err_code"])
364366

365367
self._tplinksmartplug_logger.debug(chk)
366368
if chk == 0:
@@ -372,7 +374,7 @@ def turn_on(self, plugip):
372374
t = threading.Timer(int(plug["sysCmdOnDelay"]), os.system, args=[plug["sysRunCmdOn"]])
373375
t.daemon = True
374376
t.start()
375-
if self.powerOffWhenIdle == True and plug["automaticShutdownEnabled"] == True:
377+
if self.powerOffWhenIdle is True and plug["automaticShutdownEnabled"] is True:
376378
self._tplinksmartplug_logger.debug("Resetting idle timer since plug %s was just turned on." % plugip)
377379
self._waitForHeaters = False
378380
self._reset_idle_timer()
@@ -392,13 +394,10 @@ def turn_off(self, plugip):
392394
plug_num = -1
393395
if plug["useCountdownRules"] and int(plug["countdownOffDelay"]) > 0:
394396
self.sendCommand(json.loads('{"count_down":{"delete_all_rules":null}}'), plug_ip, plug_num)
395-
chk = self.lookup(self.sendCommand(json.loads(
396-
'{"count_down":{"add_rule":{"enable":1,"delay":%s,"act":0,"name":"turn off"}}}' % plug[
397-
"countdownOffDelay"]), plug_ip, plug_num), *["count_down", "add_rule", "err_code"])
397+
chk = self.lookup(self.sendCommand(json.loads('{"count_down":{"add_rule":{"enable":1,"delay":%s,"act":0,"name":"turn off"}}}' % plug["countdownOffDelay"]), plug_ip, plug_num), *["count_down", "add_rule", "err_code"])
398398
if chk == 0:
399399
self._countdown_active = True
400-
c = threading.Timer(int(plug["countdownOffDelay"]) + 3, self._plugin_manager.send_plugin_message,
401-
[self._identifier, dict(check_status=True, ip=plugip)])
400+
c = threading.Timer(int(plug["countdownOffDelay"]) + 3, self._plugin_manager.send_plugin_message, [self._identifier, dict(check_status=True, ip=plugip)])
402401
c.start()
403402

404403
if plug["sysCmdOff"]:
@@ -411,12 +410,10 @@ def turn_off(self, plugip):
411410

412411
if not plug["useCountdownRules"]:
413412
turn_off_cmnd = dict(system=dict(set_relay_state=dict(state=0)))
414-
chk = self.lookup(self.sendCommand(turn_off_cmnd, plug_ip, plug_num),
415-
*["system", "set_relay_state", "err_code"])
413+
chk = self.lookup(self.sendCommand(turn_off_cmnd, plug_ip, plug_num), *["system", "set_relay_state", "err_code"])
416414

417415
self._tplinksmartplug_logger.debug(chk)
418416
if chk == 0:
419-
self._stop_idle_timer()
420417
return self.check_status(plugip)
421418

422419
def check_statuses(self):
@@ -481,9 +478,7 @@ def check_status(self, plugip):
481478
if self.db_path is not None:
482479
db = sqlite3.connect(self.db_path)
483480
cursor = db.cursor()
484-
cursor.execute(
485-
'''INSERT INTO energy_data(ip, timestamp, current, power, total, voltage) VALUES(?,?,?,?,?,?)''',
486-
[plugip, today.isoformat(' '), c, p, t, v])
481+
cursor.execute('''INSERT INTO energy_data(ip, timestamp, current, power, total, voltage) VALUES(?,?,?,?,?,?)''',[plugip, today.isoformat(' '), c, p, t, v])
487482
db.commit()
488483
db.close()
489484

@@ -534,9 +529,7 @@ def on_api_command(self, command, data):
534529
elif command == 'getEnergyData':
535530
db = sqlite3.connect(self.db_path)
536531
cursor = db.cursor()
537-
cursor.execute(
538-
'''SELECT timestamp, current, power, total, voltage FROM energy_data WHERE ip=? ORDER BY timestamp DESC LIMIT ?,?''',
539-
(data["ip"], data["record_offset"], data["record_limit"]))
532+
cursor.execute('''SELECT timestamp, current, power, total, voltage FROM energy_data WHERE ip=? ORDER BY timestamp DESC LIMIT ?,?''', (data["ip"], data["record_offset"], data["record_limit"]))
540533
response = {'energy_data': cursor.fetchall()}
541534
db.close()
542535
self._tplinksmartplug_logger.debug(response)
@@ -571,16 +564,14 @@ def on_api_command(self, command, data):
571564
elif command == "getListPlug":
572565
return json.dumps(self._settings.get(["arrSmartplugs"]))
573566
else:
574-
response = dict(ip=data.ip, currentState="unknown")
567+
response = dict(ip="{ip}".format(**data), currentState="unknown")
575568
if command == "enableAutomaticShutdown" or command == "disableAutomaticShutdown":
576569
self._tplinksmartplug_logger.debug("Automatic power off setting changed: %s" % self.powerOffWhenIdle)
577570
self._settings.set_boolean(["powerOffWhenIdle"], self.powerOffWhenIdle)
578571
self._settings.save()
579572
# eventManager().fire(Events.SETTINGS_UPDATED)
580573
if command == "enableAutomaticShutdown" or command == "disableAutomaticShutdown" or command == "abortAutomaticShutdown":
581-
self._plugin_manager.send_plugin_message(self._identifier,
582-
dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout",
583-
timeout_value=self._timeout_value))
574+
self._plugin_manager.send_plugin_message(self._identifier, dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout", timeout_value=self._timeout_value))
584575
else:
585576
return flask.jsonify(response)
586577

@@ -608,10 +599,9 @@ def on_event(self, event, payload):
608599
# Client Opened Event
609600
if event == Events.CLIENT_OPENED:
610601
if self._settings.get_boolean(["powerOffWhenIdle"]):
602+
self._tplinksmartplug_logger.debug("resetting idle timer due to %s event." % event)
611603
self._reset_idle_timer()
612-
self._plugin_manager.send_plugin_message(self._identifier,
613-
dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout",
614-
timeout_value=self._timeout_value))
604+
self._plugin_manager.send_plugin_message(self._identifier, dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout", timeout_value=self._timeout_value))
615605
return
616606
# Cancelled Print Interpreted Event
617607
if event == Events.PRINT_FAILED and not self._printer.is_closed_or_error():
@@ -639,9 +629,7 @@ def on_event(self, event, payload):
639629
if self._idleTimer is not None:
640630
self._reset_idle_timer()
641631
self._timeout_value = None
642-
self._plugin_manager.send_plugin_message(self._identifier,
643-
dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout",
644-
timeout_value=self._timeout_value))
632+
self._plugin_manager.send_plugin_message(self._identifier, dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout", timeout_value=self._timeout_value))
645633

646634
if event == Events.PRINT_STARTED and self._countdown_active:
647635
for plug in self._settings.get(["arrSmartplugs"]):
@@ -672,8 +660,7 @@ def on_event(self, event, payload):
672660
self._tplinksmartplug_logger.debug("power total cost: %s" % power_cost)
673661

674662
self._storage_interface = self._file_manager._storage(payload.get("origin", "local"))
675-
self._storage_interface.set_additional_metadata(payload.get("path"), "statistics", dict(
676-
lastPowerCost=dict(_default=float('{:.4f}'.format(power_cost)))), merge=True)
663+
self._storage_interface.set_additional_metadata(payload.get("path"), "statistics", dict(lastPowerCost=dict(_default=float('{:.4f}'.format(power_cost)))), merge=True)
677664

678665
self.print_job_power = 0.0
679666
self.print_job_started = False
@@ -696,18 +683,15 @@ def on_event(self, event, payload):
696683
# File Uploaded Event
697684
if event == Events.UPLOAD and self._settings.getBoolean(["event_on_upload_monitoring"]):
698685
if payload.get("print", False): # implemented in OctoPrint version 1.4.1
699-
self._tplinksmartplug_logger.debug(
700-
"File uploaded: %s. Turning enabled plugs on." % payload.get("name", ""))
686+
self._tplinksmartplug_logger.debug("File uploaded: %s. Turning enabled plugs on." % payload.get("name", ""))
701687
self._tplinksmartplug_logger.debug(payload)
702688
for plug in self._settings.get(['arrSmartplugs']):
703689
self._tplinksmartplug_logger.debug(plug)
704690
if plug["event_on_upload"] is True and not self._printer.is_ready():
705691
self._tplinksmartplug_logger.debug("powering on %s due to %s event." % (plug["ip"], event))
706692
response = self.turn_on(plug["ip"])
707693
if response["currentState"] == "on":
708-
self._tplinksmartplug_logger.debug(
709-
"power on successful for %s attempting connection in %s seconds" % (
710-
plug["ip"], plug.get("autoConnectDelay", "0")))
694+
self._tplinksmartplug_logger.debug("power on successful for %s attempting connection in %s seconds" % (plug["ip"], plug.get("autoConnectDelay", "0")))
711695
self._plugin_manager.send_plugin_message(self._identifier, response)
712696
if payload.get("path", False) and payload.get("target") == "local":
713697
self._autostart_file = payload.get("path")
@@ -749,14 +733,13 @@ def _idle_poweroff(self):
749733
if self._printer.is_printing() or self._printer.is_paused():
750734
return
751735

752-
if (uptime()/60) <= (self._settings.get_int(["idleTimeout"])):
736+
if (uptime() / 60) <= (self._settings.get_int(["idleTimeout"])):
753737
self._tplinksmartplug_logger.debug("Just booted so wait for time sync.")
754-
self._tplinksmartplug_logger.debug("uptime: {}, comparison: {}".format((uptime()/60), (self._settings.get_int(["idleTimeout"]))))
738+
self._tplinksmartplug_logger.debug("uptime: {}, comparison: {}".format((uptime() / 60), (self._settings.get_int(["idleTimeout"]))))
755739
self._reset_idle_timer()
756740
return
757741

758-
self._tplinksmartplug_logger.debug(
759-
"Idle timeout reached after %s minute(s). Turning heaters off prior to powering off plugs." % self.idleTimeout)
742+
self._tplinksmartplug_logger.debug("Idle timeout reached after %s minute(s). Turning heaters off prior to powering off plugs." % self.idleTimeout)
760743
if self._wait_for_heaters():
761744
self._tplinksmartplug_logger.debug("Heaters below temperature.")
762745
if self._wait_for_timelapse():
@@ -841,8 +824,7 @@ def _wait_for_heaters(self):
841824
self._waitForHeaters = False
842825
return True
843826

844-
self._tplinksmartplug_logger.debug(
845-
"Waiting for heaters(%s) before shutting power off..." % ', '.join(heaters_above_waittemp))
827+
self._tplinksmartplug_logger.debug("Waiting for heaters(%s) before shutting power off..." % ', '.join(heaters_above_waittemp))
846828
time.sleep(5)
847829

848830
##~~ Abort Power Off Timer
@@ -862,9 +844,7 @@ def _timer_task(self):
862844
return
863845

864846
self._timeout_value -= 1
865-
self._plugin_manager.send_plugin_message(self._identifier,
866-
dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout",
867-
timeout_value=self._timeout_value))
847+
self._plugin_manager.send_plugin_message(self._identifier, dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout", timeout_value=self._timeout_value))
868848
if self._timeout_value <= 0:
869849
if self._abort_timer is not None:
870850
self._abort_timer.cancel()
@@ -877,6 +857,7 @@ def _shutdown_system(self):
877857
if plug.get("automaticShutdownEnabled", False):
878858
response = self.turn_off("{ip}".format(**plug))
879859
self._plugin_manager.send_plugin_message(self._identifier, response)
860+
self._stop_idle_timer()
880861

881862
##~~ Utilities
882863

@@ -1036,8 +1017,6 @@ def processGCODE(self, comm_instance, phase, cmd, cmd_type, gcode, *args, **kwar
10361017
return
10371018

10381019
def processAtCommand(self, comm_instance, phase, command, parameters, tags=None, *args, **kwargs):
1039-
self._logger.info(command)
1040-
self._logger.info(parameters)
10411020
if command == "TPLINKON":
10421021
plugip = parameters
10431022
self._tplinksmartplug_logger.debug("Received @TPLINKON command, attempting power on of %s." % plugip)
@@ -1069,9 +1048,7 @@ def processAtCommand(self, comm_instance, phase, command, parameters, tags=None,
10691048
self._abort_timer = None
10701049
self._timeout_value = None
10711050
if command in ["TPLINKIDLEON", "TPLINKIDLEOFF"]:
1072-
self._plugin_manager.send_plugin_message(self._identifier,
1073-
dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout",
1074-
timeout_value=self._timeout_value))
1051+
self._plugin_manager.send_plugin_message(self._identifier, dict(powerOffWhenIdle=self.powerOffWhenIdle, type="timeout", timeout_value=self._timeout_value))
10751052

10761053
##~~ Temperatures received hook
10771054

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
plugin_name = "OctoPrint-TPLinkSmartplug"
1515

1616
# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
17-
plugin_version = "1.0.0rc2"
17+
plugin_version = "1.0.0rc3"
1818

1919
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
2020
# module

0 commit comments

Comments
 (0)