mirror of https://github.com/arendst/Tasmota.git
Berry `debug_panel.tapp` to display real-time heap and wifi rssi (#20436)
This commit is contained in:
parent
883d34d81e
commit
8a012452e8
|
@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
|
||||||
- Berry GPIO viewer initial version using async webserver (#20416)
|
- Berry GPIO viewer initial version using async webserver (#20416)
|
||||||
- Berry add `string` to `bytes()` (#20420)
|
- Berry add `string` to `bytes()` (#20420)
|
||||||
- Berry button to dynamically load GPIO Viewer with Berry backend (#20424)
|
- Berry button to dynamically load GPIO Viewer with Berry backend (#20424)
|
||||||
|
- Berry `debug_panel.tapp` to display real-time heap and wifi rssi
|
||||||
|
|
||||||
### Breaking Changed
|
### Breaking Changed
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# demo for debug panel
|
||||||
|
#
|
||||||
|
# rm debug_panel.tapp; zip -j -0 debug_panel.tapp webserver_async.be debug_panel.be autoexec.be
|
||||||
|
import webserver_async
|
||||||
|
import debug_panel
|
||||||
|
|
||||||
|
if tasmota.version() >= 0xD030002
|
||||||
|
if !tasmota.wifi()['up']
|
||||||
|
tasmota.add_rule("Wifi#Connected", def ()
|
||||||
|
global._debug_panel = debug_panel(5550)
|
||||||
|
tasmota.remove_rule("Wifi#Connected", "debug_panel_start")
|
||||||
|
end, "debug_panel_start")
|
||||||
|
else
|
||||||
|
global._debug_panel = debug_panel(5550)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log("BRY: 'debug_panel' requires Tasmota v13.3.0.2")
|
||||||
|
end
|
|
@ -0,0 +1,179 @@
|
||||||
|
#
|
||||||
|
# debug_panel.be - implements a small panel on top of the Tasmota UI to view real-time information
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Stephan Hadinger & Theo Arends
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
class debug_panel
|
||||||
|
var port
|
||||||
|
var web
|
||||||
|
var sampling_interval
|
||||||
|
#
|
||||||
|
var payload1, payload2 # temporary object bytes() to avoid reallocation
|
||||||
|
|
||||||
|
static var SAMPLING = 100
|
||||||
|
static var HTML_HEAD1 =
|
||||||
|
"<!DOCTYPE HTML><html><head>"
|
||||||
|
static var HTML_URL_F =
|
||||||
|
"<script>"
|
||||||
|
"var event_url='http://%s:%i/info_feed';"
|
||||||
|
"</script>"
|
||||||
|
static var HTML_HEAD2 =
|
||||||
|
"<script>"
|
||||||
|
"var source = new EventSource(event_url);"
|
||||||
|
|
||||||
|
'function initEventSource() {'
|
||||||
|
'source.addEventListener('
|
||||||
|
'"free_heap",'
|
||||||
|
'function (e) {'
|
||||||
|
'var freeHeap = document.getElementById("freeheap");'
|
||||||
|
'if (freeHeap) {'
|
||||||
|
'freeHeap.innerHTML = e.data;'
|
||||||
|
'}'
|
||||||
|
'},'
|
||||||
|
'false'
|
||||||
|
');'
|
||||||
|
'source.addEventListener('
|
||||||
|
'"wifi_rssi",'
|
||||||
|
'function (e) {'
|
||||||
|
'var wifirssi = document.getElementById("wifirssi");'
|
||||||
|
'if (wifirssi) {'
|
||||||
|
'wifirssi.innerHTML = e.data;'
|
||||||
|
'}'
|
||||||
|
'},'
|
||||||
|
'false'
|
||||||
|
');'
|
||||||
|
'};'
|
||||||
|
'window.addEventListener("load", initEventSource);'
|
||||||
|
"</script>"
|
||||||
|
"</head>"
|
||||||
|
"<body><style> body{ font-family: verdana,sans-serif; color: #aaa; font-size: 11px; margin:0px;}</style>"
|
||||||
|
static var HTML_CONTENT =
|
||||||
|
'<table style="width:100%;" border="0";margin:0px;><tr>'
|
||||||
|
'<td width="110">Free Heap <span id="freeheap">--- KB</span></td>'
|
||||||
|
'<td width="90">Wifi RSSI <span id="wifirssi">--%</span></td><td></td>'
|
||||||
|
'</tr></table>'
|
||||||
|
static var HTML_END =
|
||||||
|
"</body></html>"
|
||||||
|
|
||||||
|
def init(port)
|
||||||
|
self.port = port
|
||||||
|
self.web = webserver_async(port)
|
||||||
|
self.sampling_interval = self.SAMPLING
|
||||||
|
self.payload1 = bytes(100) # reserve 100 bytes by default
|
||||||
|
self.payload2 = bytes(100) # reserve 100 bytes by default
|
||||||
|
|
||||||
|
self.web.set_chunked(true)
|
||||||
|
self.web.set_cors(true)
|
||||||
|
self.web.on("/info_feed", self, self.send_info_feed)
|
||||||
|
self.web.on("/info", self, self.send_info_page)
|
||||||
|
|
||||||
|
tasmota.add_driver(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def close()
|
||||||
|
tasmota.remove_driver(self)
|
||||||
|
self.web.close()
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_info_page(cnx, uri, verb)
|
||||||
|
import string
|
||||||
|
|
||||||
|
var host = cnx.header_host
|
||||||
|
var host_split = string.split(host, ':') # need to make it stronger
|
||||||
|
var ip = host_split[0]
|
||||||
|
var port = 80
|
||||||
|
if size(host_split) > 1
|
||||||
|
port = int(host_split[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
cnx.send(200, "text/html")
|
||||||
|
cnx.write(self.HTML_HEAD1)
|
||||||
|
cnx.write(format(self.HTML_URL_F, ip, port))
|
||||||
|
cnx.write(self.HTML_HEAD2)
|
||||||
|
cnx.write(self.HTML_CONTENT)
|
||||||
|
cnx.write(self.HTML_END)
|
||||||
|
|
||||||
|
cnx.content_stop()
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_info_feed(cnx, uri, verb)
|
||||||
|
cnx.set_chunked(false) # no chunking since we use EventSource
|
||||||
|
cnx.send(200, "text/event-stream")
|
||||||
|
self.send_info_tick(cnx)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_info_tick(cnx)
|
||||||
|
if cnx.buf_out_empty()
|
||||||
|
# if out buffer is not empty, do not send any new information
|
||||||
|
var payload
|
||||||
|
# send free heap
|
||||||
|
payload = f"id:{tasmota.millis()}\r\n"
|
||||||
|
"event:free_heap\r\n"
|
||||||
|
"data:{tasmota.memory().find('heap_free', 0)} KB\r\n\r\n"
|
||||||
|
cnx.write(payload)
|
||||||
|
|
||||||
|
# send wifi rssi
|
||||||
|
payload = f"id:{tasmota.millis()}\r\n"
|
||||||
|
"event:wifi_rssi\r\n"
|
||||||
|
"data:{tasmota.wifi().find('quality', '--')}%\r\n\r\n"
|
||||||
|
cnx.write(payload)
|
||||||
|
end
|
||||||
|
|
||||||
|
tasmota.set_timer(self.sampling_interval, def () self.send_info_tick(cnx) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add button 'GPIO Viewer' redirects to '/part_wiz?'
|
||||||
|
def web_add_console_button()
|
||||||
|
self.send_iframe_code()
|
||||||
|
end
|
||||||
|
def web_add_main_button()
|
||||||
|
self.send_iframe_code()
|
||||||
|
end
|
||||||
|
def web_add_management_button()
|
||||||
|
self.send_iframe_code()
|
||||||
|
end
|
||||||
|
def web_add_config_button()
|
||||||
|
self.send_iframe_code()
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_iframe_code()
|
||||||
|
import webserver
|
||||||
|
var ip = tasmota.wifi().find('ip')
|
||||||
|
if (ip == nil)
|
||||||
|
ip = tasmota.eth().find('ip')
|
||||||
|
end
|
||||||
|
if (ip != nil)
|
||||||
|
webserver.content_send(
|
||||||
|
f'<div style="left: 0px; border: 0px none; background-color: #252525; height: 28px; position: fixed; width: 340px; overflow: hidden; padding: 0px 0px; top: 0px; left: 50%; transform: translateX(-50%);">'
|
||||||
|
'<iframe src="http://{ip}:{self.port}/info" scrolling="no" '
|
||||||
|
'style="color:#eaeaea; border:0px none;height:20px;width:340px;margin:0px 8px 0px 8px;padding:0px 0px;">'
|
||||||
|
'</iframe>'
|
||||||
|
'<hr style="margin:0px;">'
|
||||||
|
'</div>')
|
||||||
|
# f"<form style='display: block;' action='http://{ip}:{self.port}/' method='post' target='_blank'><button>GPIO Viewer</button></form><p></p>")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return debug_panel
|
||||||
|
|
||||||
|
# if tasmota
|
||||||
|
# global.debug_panel = Debug_panel(8887)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# return global.debug_panel
|
Binary file not shown.
|
@ -198,7 +198,7 @@ class Webserver_async_cnx
|
||||||
# pre: self.buf_in is not empty
|
# pre: self.buf_in is not empty
|
||||||
# post: self.buf_in has made progress (smaller or '')
|
# post: self.buf_in has made progress (smaller or '')
|
||||||
def parse()
|
def parse()
|
||||||
tasmota.log(f"WEB: incoming {bytes().fromstring(self.buf_in).tohex()}", 3)
|
# tasmota.log(f"WEB: incoming {bytes().fromstring(self.buf_in).tohex()}", 3)
|
||||||
if self.phase == 0
|
if self.phase == 0
|
||||||
self.parse_http_req_line()
|
self.parse_http_req_line()
|
||||||
elif self.phase == 1
|
elif self.phase == 1
|
||||||
|
@ -274,7 +274,7 @@ class Webserver_async_cnx
|
||||||
#
|
#
|
||||||
# Received header
|
# Received header
|
||||||
def event_http_header(header_key, header_value)
|
def event_http_header(header_key, header_value)
|
||||||
tasmota.log(f"WEB: header key '{header_key}' = '{header_value}'")
|
# tasmota.log(f"WEB: header key '{header_key}' = '{header_value}'")
|
||||||
|
|
||||||
if (header_key == "Host")
|
if (header_key == "Host")
|
||||||
self.header_host = header_value
|
self.header_host = header_value
|
||||||
|
@ -291,7 +291,7 @@ class Webserver_async_cnx
|
||||||
#############################################################
|
#############################################################
|
||||||
# parse incoming payload (if any)
|
# parse incoming payload (if any)
|
||||||
def parse_http_payload()
|
def parse_http_payload()
|
||||||
tasmota.log(f"WEB: parsing payload '{bytes().fromstring(self.buf_in).tohex()}'")
|
# tasmota.log(f"WEB: parsing payload '{bytes().fromstring(self.buf_in).tohex()}'")
|
||||||
# dispatch request before parsing payload
|
# dispatch request before parsing payload
|
||||||
self.server.dispatch(self, self.req_uri, self.req_verb)
|
self.server.dispatch(self, self.req_uri, self.req_verb)
|
||||||
end
|
end
|
||||||
|
@ -538,7 +538,7 @@ class webserver_async
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#return webserver_async
|
return webserver_async
|
||||||
|
|
||||||
#- Test
|
#- Test
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue