Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Berry debug_panel.tapp to display real-time heap and wifi rssi #20436

Merged
merged 1 commit into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 add `string` to `bytes()` (#20420)
- 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

Expand Down
18 changes: 18 additions & 0 deletions tasmota/berry/gpio_viewer/autoexec.be
Original file line number Diff line number Diff line change
@@ -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
179 changes: 179 additions & 0 deletions tasmota/berry/gpio_viewer/debug_panel.be
Original file line number Diff line number Diff line change
@@ -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 added tasmota/berry/gpio_viewer/debug_panel.tapp
Binary file not shown.
8 changes: 4 additions & 4 deletions tasmota/berry/gpio_viewer/webserver_async.be
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class Webserver_async_cnx
# pre: self.buf_in is not empty
# post: self.buf_in has made progress (smaller or '')
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
self.parse_http_req_line()
elif self.phase == 1
Expand Down Expand Up @@ -274,7 +274,7 @@ class Webserver_async_cnx
#
# Received header
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")
self.header_host = header_value
Expand All @@ -291,7 +291,7 @@ class Webserver_async_cnx
#############################################################
# parse incoming payload (if any)
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
self.server.dispatch(self, self.req_uri, self.req_verb)
end
Expand Down Expand Up @@ -538,7 +538,7 @@ class webserver_async

end

#return webserver_async
return webserver_async

#- Test

Expand Down