1313import threading
1414
1515class 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
0 commit comments