Skip to content

Commit 1b8b068

Browse files
authored
0.8.6
**Added** - configurable color options for the navbar icons. - countdown timer that utilizes the backlog command with delay to allow for powering off a plug after the pi has been shutdown using the system command option. - polling option to check status based on configured interval.
1 parent a9cc240 commit 1b8b068

File tree

6 files changed

+252
-169
lines changed

6 files changed

+252
-169
lines changed

octoprint_tasmota/__init__.py

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@
1313
import threading
1414

1515
class tasmotaPlugin(octoprint.plugin.SettingsPlugin,
16-
octoprint.plugin.AssetPlugin,
17-
octoprint.plugin.TemplatePlugin,
16+
octoprint.plugin.AssetPlugin,
17+
octoprint.plugin.TemplatePlugin,
1818
octoprint.plugin.SimpleApiPlugin,
1919
octoprint.plugin.StartupPlugin):
20-
20+
2121
def __init__(self):
2222
self._logger = logging.getLogger("octoprint.plugins.tasmota")
2323
self._tasmota_logger = logging.getLogger("octoprint.plugins.tasmota.debug")
24-
24+
2525
##~~ StartupPlugin mixin
26-
26+
2727
def on_startup(self, host, port):
2828
# setup customized logger
2929
from octoprint.logging.handlers import CleaningTimedRotatingFileHandler
@@ -34,20 +34,22 @@ def on_startup(self, host, port):
3434
self._tasmota_logger.addHandler(tasmota_logging_handler)
3535
self._tasmota_logger.setLevel(logging.DEBUG if self._settings.get_boolean(["debug_logging"]) else logging.INFO)
3636
self._tasmota_logger.propagate = False
37-
37+
3838
def on_after_startup(self):
3939
self._logger.info("Tasmota loaded!")
40-
40+
4141
##~~ SettingsPlugin mixin
42-
42+
4343
def get_settings_defaults(self):
4444
return dict(
4545
singleRelay = True,
4646
debug_logging = False,
47-
arrSmartplugs = [{'ip':'','displayWarning':True,'idx':'1','warnPrinting':False,'gcodeEnabled':False,'gcodeOnDelay':0,'gcodeOffDelay':0,'autoConnect':True,'autoConnectDelay':10.0,'autoDisconnect':True,'autoDisconnectDelay':0,'sysCmdOn':False,'sysRunCmdOn':'','sysCmdOnDelay':0,'sysCmdOff':False,'sysRunCmdOff':'','sysCmdOffDelay':0,'currentState':'unknown','btnColor':'#808080','username':'admin','password':'','icon':'icon-bolt','label':''}],
47+
polling_enabled = False,
48+
polling_interval = 0,
49+
arrSmartplugs = [{'ip':'','displayWarning':True,'idx':'1','warnPrinting':False,'gcodeEnabled':False,'gcodeOnDelay':0,'gcodeOffDelay':0,'autoConnect':True,'autoConnectDelay':10.0,'autoDisconnect':True,'autoDisconnectDelay':0,'sysCmdOn':False,'sysRunCmdOn':'','sysCmdOnDelay':0,'sysCmdOff':False,'sysRunCmdOff':'','sysCmdOffDelay':0,'currentState':'unknown','username':'admin','password':'','icon':'icon-bolt','label':'','on_color':'#00FF00','off_color':'#FF0000','unknown_color':'#808080','use_backlog':False,'backlog_on_delay':0,'backlog_off_delay':0}],
4850
)
49-
50-
def on_settings_save(self, data):
51+
52+
def on_settings_save(self, data):
5153
old_debug_logging = self._settings.get_boolean(["debug_logging"])
5254

5355
octoprint.plugin.SettingsPlugin.on_settings_save(self, data)
@@ -58,47 +60,52 @@ def on_settings_save(self, data):
5860
self._tasmota_logger.setLevel(logging.DEBUG)
5961
else:
6062
self._tasmota_logger.setLevel(logging.INFO)
61-
63+
6264
def get_settings_version(self):
63-
return 3
64-
65+
return 4
66+
6567
def on_settings_migrate(self, target, current=None):
6668
if current is None or current < self.get_settings_version():
6769
# Reset plug settings to defaults.
6870
self._logger.debug("Resetting arrSmartplugs for tasmota settings.")
6971
self._settings.set(['arrSmartplugs'], self.get_settings_defaults()["arrSmartplugs"])
70-
72+
7173
##~~ AssetPlugin mixin
7274

7375
def get_assets(self):
7476
return dict(
7577
js=["js/tasmota.js"],
7678
css=["css/tasmota.css"]
7779
)
78-
80+
7981
##~~ TemplatePlugin mixin
80-
82+
8183
def get_template_configs(self):
8284
return [
8385
dict(type="navbar", custom_bindings=True),
8486
dict(type="settings", custom_bindings=True)
8587
]
86-
88+
8789
##~~ SimpleApiPlugin mixin
88-
89-
def turn_on(self, plugip, plugidx, username="admin", password=""):
90+
91+
def turn_on(self, plugip, plugidx, username="admin", password="", backlog_delay=0):
9092
if self._settings.get(['singleRelay']):
9193
plugidx = ''
9294
self._tasmota_logger.debug("Turning on %s index %s." % (plugip, plugidx))
9395
try:
94-
webresponse = urllib2.urlopen("http://" + plugip + "/cm?user=" + username + "&password=" + password + "&cmnd=Power" + str(plugidx) + "%20on").read()
95-
response = json.loads(webresponse)
96+
if int(backlog_delay) > 0:
97+
webresponse = urllib2.urlopen("http://" + plugip + "/cm?user=" + username + "&password=" + password + "&cmnd=backlog%20delay%20" + str(int(backlog_delay)*10) + "%3BPower" + str(plugidx) + "%20on%3B").read()
98+
response = dict()
99+
response["POWER%s" % plugidx] = "ON"
100+
else:
101+
webresponse = urllib2.urlopen("http://" + plugip + "/cm?user=" + username + "&password=" + password + "&cmnd=Power" + str(plugidx) + "%20on").read()
102+
response = json.loads(webresponse)
96103
chk = response["POWER%s" % plugidx]
97-
except:
104+
except:
98105
self._tasmota_logger.error('Invalid ip or unknown error connecting to %s.' % plugip, exc_info=True)
99106
response = "Unknown error turning on %s index %s." % (plugip, plugidx)
100107
chk = "UNKNOWN"
101-
108+
102109
self._tasmota_logger.debug("Response: %s" % response)
103110
if self._settings.get(['singleRelay']):
104111
plugidx = '1'
@@ -109,20 +116,25 @@ def turn_on(self, plugip, plugidx, username="admin", password=""):
109116
else:
110117
self._tasmota_logger.debug(response)
111118
self._plugin_manager.send_plugin_message(self._identifier, dict(currentState="unknown",ip=plugip,idx=plugidx))
112-
113-
def turn_off(self, plugip, plugidx, username="admin", password=""):
119+
120+
def turn_off(self, plugip, plugidx, username="admin", password="", backlog_delay=0):
114121
if self._settings.get(['singleRelay']):
115122
plugidx = ''
116123
self._tasmota_logger.debug("Turning off %s index %s." % (plugip, plugidx))
117124
try:
118-
webresponse = urllib2.urlopen("http://" + plugip + "/cm?user=" + username + "&password=" + password + "&cmnd=Power" + str(plugidx) + "%20off").read()
119-
response = json.loads(webresponse)
125+
if int(backlog_delay) > 0:
126+
webresponse = urllib2.urlopen("http://" + plugip + "/cm?user=" + username + "&password=" + password + "&cmnd=backlog%20delay%20" + str(int(backlog_delay)*10) + "%3BPower" + str(plugidx) + "%20off%3B").read()
127+
response = dict()
128+
response["POWER%s" % plugidx] = "OFF"
129+
else:
130+
webresponse = urllib2.urlopen("http://" + plugip + "/cm?user=" + username + "&password=" + password + "&cmnd=Power" + str(plugidx) + "%20off").read()
131+
response = json.loads(webresponse)
120132
chk = response["POWER%s" % plugidx]
121133
except:
122134
self._tasmota_logger.error('Invalid ip or unknown error connecting to %s.' % plugip, exc_info=True)
123135
response = "Unknown error turning off %s index %s." % (plugip, plugidx)
124136
chk = "UNKNOWN"
125-
137+
126138
self._tasmota_logger.debug("Response: %s" % response)
127139
if self._settings.get(['singleRelay']):
128140
plugidx = '1'
@@ -133,7 +145,7 @@ def turn_off(self, plugip, plugidx, username="admin", password=""):
133145
else:
134146
self._tasmota_logger.debug(response)
135147
self._plugin_manager.send_plugin_message(self._identifier, dict(currentState="unknown",ip=plugip,idx=plugidx))
136-
148+
137149
def check_status(self, plugip, plugidx, username="admin", password=""):
138150
if self._settings.get(['singleRelay']):
139151
plugidx = ''
@@ -148,7 +160,7 @@ def check_status(self, plugip, plugidx, username="admin", password=""):
148160
self._tasmota_logger.error('Invalid ip or unknown error connecting to %s.' % plugip, exc_info=True)
149161
response = "unknown error with %s." % plugip
150162
chk = "UNKNOWN"
151-
163+
152164
self._tasmota_logger.debug("%s index %s is %s" % (plugip, plugidx, chk))
153165
if self._settings.get(['singleRelay']):
154166
plugidx = '1'
@@ -158,8 +170,8 @@ def check_status(self, plugip, plugidx, username="admin", password=""):
158170
self._plugin_manager.send_plugin_message(self._identifier, dict(currentState="off",ip=plugip,idx=plugidx))
159171
else:
160172
self._tasmota_logger.debug(response)
161-
self._plugin_manager.send_plugin_message(self._identifier, dict(currentState="unknown",ip=plugip,idx=plugidx))
162-
173+
self._plugin_manager.send_plugin_message(self._identifier, dict(currentState="unknown",ip=plugip,idx=plugidx))
174+
163175
def get_api_commands(self):
164176
return dict(turnOn=["ip","idx"],turnOff=["ip","idx"],checkStatus=["ip","idx"],connectPrinter=[],disconnectPrinter=[],sysCommand=["cmd"])
165177

@@ -168,18 +180,18 @@ def on_api_command(self, command, data):
168180
if not user_permission.can():
169181
from flask import make_response
170182
return make_response("Insufficient rights", 403)
171-
183+
172184
if command == 'turnOn':
173185
if "username" in data and data["username"] != "":
174186
self._tasmota_logger.debug("Using authentication for %s." % "{ip}".format(**data))
175-
self.turn_on("{ip}".format(**data),"{idx}".format(**data),username="{username}".format(**data),password="{password}".format(**data))
187+
self.turn_on("{ip}".format(**data),"{idx}".format(**data),username="{username}".format(**data),password="{password}".format(**data),backlog_delay="{backlog_delay}".format(**data))
176188
else:
177189
self.turn_on("{ip}".format(**data),"{idx}".format(**data))
178190
elif command == 'turnOff':
179191
if "username" in data and data["username"] != "":
180192
self._tasmota_logger.debug("Using authentication for %s." % "{ip}".format(**data))
181-
self.turn_off("{ip}".format(**data),"{idx}".format(**data),username="{username}".format(**data),password="{password}".format(**data))
182-
else:
193+
self.turn_off("{ip}".format(**data),"{idx}".format(**data),username="{username}".format(**data),password="{password}".format(**data),backlog_delay="{backlog_delay}".format(**data))
194+
else:
183195
self.turn_off("{ip}".format(**data),"{idx}".format(**data))
184196
elif command == 'checkStatus':
185197
if "username" in data and data["username"] != "":
@@ -196,30 +208,36 @@ def on_api_command(self, command, data):
196208
elif command == 'sysCommand':
197209
self._tasmota_logger.debug("Running system command %s." % "{cmd}".format(**data))
198210
os.system("{cmd}".format(**data))
199-
211+
200212
##~~ Gcode processing hook
201-
213+
202214
def processGCODE(self, comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs):
203215
if gcode:
204216
if cmd.startswith("M8") and cmd.count(" ") >= 2:
205217
plugip = cmd.split()[1]
206-
plugidx = cmd.split()[2]
218+
plugidx = cmd.split()[2]
207219
for plug in self._settings.get(["arrSmartplugs"]):
208220
if plug["ip"].upper() == plugip.upper() and plug["idx"] == plugidx and plug["gcodeEnabled"]:
209221
if cmd.startswith("M80"):
210-
t = threading.Timer(int(plug["gcodeOnDelay"]),self.turn_on, [plug["ip"],plug["idx"]],{'username': plug["username"],'password': plug["password"]})
222+
if plug["sysCmdOn"] and plug["sysRunCmdOn"] != "":
223+
s = threading.Timer(int(plug["sysCmdOnDelay"]), os.system, [plug["sysRunCmdOn"]])
224+
s.start()
225+
t = threading.Timer(int(plug["gcodeOnDelay"]),self.turn_on, [plug["ip"],plug["idx"]],{'username': plug["username"],'password': plug["password"],'backlog_delay': plug["backlog_on_delay"]})
211226
t.start()
212227
self._tasmota_logger.debug("Received M80 command, attempting power on of %s index %s." % (plugip,plugidx))
213228
return
214229
elif cmd.startswith("M81"):
215-
t = threading.Timer(int(plug["gcodeOffDelay"]),self.turn_off, [plug["ip"],plug["idx"]],{'username': plug["username"],'password': plug["password"]})
230+
if plug["sysCmdOff"] and plug["sysRunCmdOff"] != "":
231+
s = threading.Timer(int(plug["sysCmdOffDelay"]), os.system, [plug["sysRunCmdOff"]])
232+
s.start()
233+
t = threading.Timer(int(plug["gcodeOffDelay"]),self.turn_off, [plug["ip"],plug["idx"]],{'username': plug["username"],'password': plug["password"],'backlog_delay': plug["backlog_off_delay"]})
216234
t.start()
217235
self._tasmota_logger.debug("Received M81 command, attempting power off of %s index %s." % (plugip,plugidx))
218236
return
219237
else:
220238
return
221239
return
222-
240+
223241

224242
##~~ Softwareupdate hook
225243

octoprint_tasmota/static/css/tasmota.css

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#navbar_plugin_tasmota > a > i.on {
1+
/* #navbar_plugin_tasmota > a > i.on {
22
color: #00FF00 !important;
33
}
44
@@ -8,12 +8,17 @@
88
99
#navbar_plugin_tasmota > a > i.unknown {
1010
color: #808080 !important;
11-
}
11+
} */
1212

1313
#navbar_plugin_tasmota > a > div.tasmota_label {
1414
display: none;
1515
}
1616

17+
#navbar_plugin_tasmota > a > i.unknown::after {
18+
content: " ?";
19+
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
20+
} }
21+
1722
/* TouchUI - Show Label */
1823
#touch #navbar_plugin_tasmota > a > div.tasmota_label {
1924
padding-left: 5px;

0 commit comments

Comments
 (0)