mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 11:16:34 +00:00
Merge pull request #8581 from Staars/touch
Command interface for touch button driver and a serial plotter
This commit is contained in:
commit
9c0fc4edcd
188
pio/serial-plotter.py
Executable file
188
pio/serial-plotter.py
Executable file
@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
serial-plotter.py - for Tasmota
|
||||
|
||||
Copyright (C) 2020 Christian Baars
|
||||
|
||||
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/>.
|
||||
|
||||
Requirements:
|
||||
- Python
|
||||
- pip3 matplotlib
|
||||
- a Tasmotadriver that plots
|
||||
|
||||
Instructions:
|
||||
expects serial data in the format:
|
||||
'PLOT: graphnumber value'
|
||||
graph (1-4)
|
||||
integer value
|
||||
Code snippet example: (last value will be ignored)
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"),button_index+1, _value, Button.touch_hits[button_index]);
|
||||
|
||||
Usage:
|
||||
set serial config in code
|
||||
./serial-plotter.py
|
||||
set output in tasmota, e.g.; TouchCal 1..4 (via Textbox)
|
||||
|
||||
"""
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
from matplotlib.widgets import TextBox
|
||||
import time
|
||||
import serial
|
||||
import argparse
|
||||
|
||||
#default values
|
||||
port = '/dev/cu.SLAB_USBtoUART'
|
||||
baud = 115200
|
||||
|
||||
#command line input
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--port", "-p", help="change serial port, default: " + port)
|
||||
parser.add_argument("--baud", "-b", help="change baud rate, default: " + str(baud))
|
||||
args = parser.parse_args()
|
||||
if args.port:
|
||||
print("change serial port to %s" % args.port)
|
||||
port = args.port
|
||||
if args.baud:
|
||||
print("change baud rate to %s" % args.baud)
|
||||
baud = args.baud
|
||||
|
||||
|
||||
#time range
|
||||
dt = 0.01
|
||||
t = np.arange(0.0, 100, dt)
|
||||
|
||||
#lists for the data
|
||||
xs = [0] #counting up x
|
||||
ys = [[0],[0],[0],[0]] #4 fixed graphs for now
|
||||
max_y = 1
|
||||
# min_y = 0
|
||||
|
||||
fig = plt.figure('Tasmota Serial Plotter')
|
||||
ax = fig.add_subplot(111, autoscale_on=True, xlim=(0, 200), ylim=(0, 20)) #fixed x scale for now, y will adapt
|
||||
ax.grid()
|
||||
|
||||
line1, = ax.plot([], [], color = "r", label='G 1')
|
||||
line2, = ax.plot([], [], color = "g", label='G 2')
|
||||
line3, = ax.plot([], [], color = "b", label='G 3')
|
||||
line4, = ax.plot([], [], color = "y", label='G 4')
|
||||
|
||||
time_template = 'time = %.1fs'
|
||||
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
|
||||
|
||||
ser = serial.Serial()
|
||||
ser.port = port
|
||||
ser.baudrate = baud
|
||||
ser.timeout = 0 #return immediately
|
||||
try:
|
||||
ser.open()
|
||||
except:
|
||||
print("Could not connect to serial with settings: " + str(ser.port) + ' at ' + str(ser.baudrate) + 'baud')
|
||||
print("port available?")
|
||||
exit()
|
||||
|
||||
if ser.is_open==True:
|
||||
print("Serial Plotter started ...:")
|
||||
plt.title('connected to ' + str(ser.port) + ' at ' + str(ser.baudrate) + 'baud')
|
||||
else:
|
||||
print("Could not connect to serial: " + str(ser.port) + ' at ' + str(ser.baudrate) + 'baud')
|
||||
plt.title('NOT connected to ' + str(ser.port) + ' at ' + str(ser.baudrate) + 'baud')
|
||||
|
||||
def init():
|
||||
line1.set_data([], [])
|
||||
line2.set_data([], [])
|
||||
line3.set_data([], [])
|
||||
line4.set_data([], [])
|
||||
time_text.set_text('')
|
||||
return [line1,line2,line3,line4,time_text ] #was line
|
||||
|
||||
|
||||
def parse_line(data_line):
|
||||
pos = data_line.find("PLOT:", 10)
|
||||
if pos<0:
|
||||
# print("wrong format")
|
||||
return 0,0
|
||||
|
||||
raw_data = data_line[pos+6:]
|
||||
val_list = raw_data.split(',')
|
||||
try:
|
||||
g = int(val_list[0])
|
||||
v = int(val_list[1])
|
||||
return g, v
|
||||
except:
|
||||
return 0,0
|
||||
|
||||
def update(num, line1, line2):
|
||||
global xs, ys, max_y
|
||||
|
||||
time_text.set_text(time_template % (num*dt) )
|
||||
|
||||
receive_data = str(ser.readline()) #string
|
||||
|
||||
g, v = parse_line(receive_data)
|
||||
if (g in range(1,5)):
|
||||
# print(v,g)
|
||||
if v>max_y:
|
||||
max_y = v
|
||||
print(max_y)
|
||||
ax.set_ylim([0, max_y * 1.2])
|
||||
|
||||
idx = 0
|
||||
for y in ys:
|
||||
y.append(y[-1])
|
||||
if idx == g-1:
|
||||
y[-1] = v
|
||||
idx = idx +1
|
||||
xs.append(xs[-1]+1)
|
||||
|
||||
if len(ys[0])>200:
|
||||
xs.pop()
|
||||
for y in ys:
|
||||
y.pop(0)
|
||||
line1.set_data(xs, ys[0])
|
||||
line2.set_data(xs, ys[1])
|
||||
line3.set_data(xs, ys[2])
|
||||
line4.set_data(xs, ys[3])
|
||||
return [line1,line2,line3,line4, time_text]
|
||||
|
||||
def handle_close(evt):
|
||||
print('Closing serial connection')
|
||||
ser.close()
|
||||
print('Closed serial plotter')
|
||||
|
||||
ani = animation.FuncAnimation(fig, update, None, fargs=[line1, line2],
|
||||
interval=10, blit=True, init_func=init)
|
||||
|
||||
ax.set_xlabel('Last 200 Samples')
|
||||
ax.set_ylabel('Values')
|
||||
|
||||
fig.canvas.mpl_connect('close_event', handle_close)
|
||||
|
||||
def submit(text):
|
||||
print (text)
|
||||
ser.write(text.encode() + "\n".encode())
|
||||
|
||||
plt.subplots_adjust(bottom=0.25)
|
||||
axbox = plt.axes([0.15, 0.05, 0.7, 0.075])
|
||||
text_box = TextBox(axbox, 'Send:', initial='')
|
||||
text_box.on_submit(submit)
|
||||
|
||||
ax.legend(loc='lower right', ncol=2)
|
||||
|
||||
if ser.is_open==True:
|
||||
plt.show()
|
||||
|
@ -319,6 +319,11 @@
|
||||
#define D_CMND_HUMOFFSET "HumOffset"
|
||||
#define D_CMND_GLOBAL_TEMP "GlobalTemp"
|
||||
#define D_CMND_GLOBAL_HUM "GlobalHum"
|
||||
#ifdef ESP32
|
||||
#define D_CMND_TOUCH_CAL "TouchCal"
|
||||
#define D_CMND_TOUCH_THRES "TouchThres"
|
||||
#define D_CMND_TOUCH_NUM "TouchNum"
|
||||
#endif //ESP32
|
||||
|
||||
// Commands xdrv_01_mqtt.ino
|
||||
#define D_CMND_MQTTLOG "MqttLog"
|
||||
|
@ -52,6 +52,14 @@ struct BUTTON {
|
||||
uint8_t adc = 99; // ADC0 button number
|
||||
} Button;
|
||||
|
||||
#ifdef ESP32
|
||||
struct TOUCH_BUTTON {
|
||||
uint8_t pin_threshold = TOUCH_PIN_THRESHOLD;
|
||||
uint8_t hit_threshold = TOUCH_HIT_THRESHOLD;
|
||||
uint8_t calibration = 0; // Bitfield
|
||||
} TOUCH_BUTTON;
|
||||
#endif // ESP32
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ButtonPullupFlag(uint8 button_bit)
|
||||
@ -155,15 +163,15 @@ void ButtonHandler(void)
|
||||
uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index));
|
||||
button = NOT_PRESSED;
|
||||
if (_value != 0){ // probably read-error
|
||||
if(_value < TOUCH_PIN_THRESHOLD){
|
||||
if(++Button.touch_hits[button_index]>TOUCH_HIT_THRESHOLD){
|
||||
button = PRESSED;
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Touch value: %u hits: %u"), _value, Button.touch_hits[button_index]);
|
||||
if(_value < TOUCH_BUTTON.pin_threshold){
|
||||
if(++Button.touch_hits[button_index]>TOUCH_BUTTON.hit_threshold){
|
||||
if (!bitRead(TOUCH_BUTTON.calibration, button_index+1)) button = PRESSED;
|
||||
}
|
||||
}
|
||||
else Button.touch_hits[button_index] = 0;
|
||||
}
|
||||
else Button.touch_hits[button_index] = 0;
|
||||
if (bitRead(TOUCH_BUTTON.calibration, button_index+1)) AddLog_P2(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"),button_index+1, _value, Button.touch_hits[button_index]); // button number (1..4) , value, continuous hits under threshold
|
||||
}
|
||||
else{ // Normal button
|
||||
button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index));
|
||||
|
@ -38,7 +38,11 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
|
||||
#endif // USE_DEVICE_GROUPS_SEND
|
||||
D_CMND_DEVGROUP_SHARE "|" D_CMND_DEVGROUPSTATUS "|"
|
||||
#endif // USE_DEVICE_GROUPS
|
||||
D_CMND_SENSOR "|" D_CMND_DRIVER;
|
||||
D_CMND_SENSOR "|" D_CMND_DRIVER
|
||||
#ifdef ESP32
|
||||
"|" D_CMND_TOUCH_CAL "|" D_CMND_TOUCH_THRES "|" D_CMND_TOUCH_NUM
|
||||
#endif //ESP32
|
||||
;
|
||||
|
||||
void (* const TasmotaCommand[])(void) PROGMEM = {
|
||||
&CmndBacklog, &CmndDelay, &CmndPower, &CmndStatus, &CmndState, &CmndSleep, &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl,
|
||||
@ -61,7 +65,11 @@ void (* const TasmotaCommand[])(void) PROGMEM = {
|
||||
#endif // USE_DEVICE_GROUPS_SEND
|
||||
&CmndDevGroupShare, &CmndDevGroupStatus,
|
||||
#endif // USE_DEVICE_GROUPS
|
||||
&CmndSensor, &CmndDriver };
|
||||
&CmndSensor, &CmndDriver
|
||||
#ifdef ESP32
|
||||
,&CmndTouchCal, &CmndTouchThres, &CmndTouchNum
|
||||
#endif //ESP32
|
||||
};
|
||||
|
||||
const char kWifiConfig[] PROGMEM =
|
||||
D_WCFG_0_RESTART "||" D_WCFG_2_WIFIMANAGER "||" D_WCFG_4_RETRY "|" D_WCFG_5_WAIT "|" D_WCFG_6_SERIAL "|" D_WCFG_7_WIFIMANAGER_RESET_ONLY;
|
||||
@ -1946,3 +1954,41 @@ void CmndDriver(void)
|
||||
{
|
||||
XdrvCall(FUNC_COMMAND_DRIVER);
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
void CmndTouchCal(void)
|
||||
{
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
if (XdrvMailbox.payload < MAX_KEYS + 1) TOUCH_BUTTON.calibration = bitSet(TOUCH_BUTTON.calibration, XdrvMailbox.payload);
|
||||
if (XdrvMailbox.payload == 0) TOUCH_BUTTON.calibration = 0;
|
||||
if (XdrvMailbox.payload == 255) TOUCH_BUTTON.calibration = 255; // all pinss
|
||||
}
|
||||
Response_P(PSTR("{\"" D_CMND_TOUCH_CAL "\": %u"), TOUCH_BUTTON.calibration);
|
||||
ResponseJsonEnd();
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("Button Touchvalue Hits,"));
|
||||
}
|
||||
|
||||
void CmndTouchThres(void)
|
||||
{
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
if (XdrvMailbox.payload<256){
|
||||
TOUCH_BUTTON.pin_threshold = XdrvMailbox.payload;
|
||||
}
|
||||
}
|
||||
Response_P(PSTR("{\"" D_CMND_TOUCH_THRES "\": %u"), TOUCH_BUTTON.pin_threshold);
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
|
||||
void CmndTouchNum(void)
|
||||
{
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
if (XdrvMailbox.payload<32){
|
||||
TOUCH_BUTTON.hit_threshold = XdrvMailbox.payload;
|
||||
}
|
||||
}
|
||||
Response_P(PSTR("{\"" D_CMND_TOUCH_NUM "\": %u"), TOUCH_BUTTON.hit_threshold);
|
||||
ResponseJsonEnd();
|
||||
|
||||
}
|
||||
|
||||
#endif //ESP32
|
Loading…
x
Reference in New Issue
Block a user