eiche
1.) ja, in einer Datei, nicht im KVS
2.) Bin mit dem while einem intuitiven, von Python Erfahrungen getriggertem Impuls gefolgt. Da würde man noch ein sleep(1000) einbauen,
gibt es aber bei Shelly nicht.
3.) Ich brauche zum jetzigen Zeitpunkt schon 2 laufende Skripte, das 3. noch zugelassene ist für etwas anderes vorgesehen.
4.) -
5.) -
Ich bin mit dem Skript jetzt schon am Limit, was die Code-Länge, (deshalb das Auslagern von Skriptteilen in non-excecutable), Aufruf von Calls (hier habe ich schon alles Mögliche in stacks verpackt), und die Nutzung des zugelassenen Ram-Speichers ist auch am Limit.
Aber, macht euch selbst ein Bild:
Skript:
//Cut value to digits
function cut(val, digit) {
val = val.toFixed(digit);
st = String(val);
st = st.slice(0, st.indexOf('.') + digit)
return parseFloat(st);
}
//Look for value in list
function includes(list, value) {
for (let i = 0; i < list.length; i++) {
if(value === list[i]) return true;
}
return false;
}
//Do some conversions on raw data
function treat_data(data, proto, host) {
try {
alarm_state = false;
raw = data;
let ruuvi = {};
ruuvi['Mac'] = raw.addr;
if(ruuvi.Mac.length < 18) {
last_oct = data.mac_5.toString(16);
if(last_oct.length < 2) last_oct = 0 + last_oct;
ruuvi.Mac += last_oct;
}
if(components[ruuvi.Mac] === undefined) return;
ruuvi['Temperatur'] = cut(raw.temp,3);
ruuvi['Luftfeuchtigkeit'] = cut(raw.humidity,3);
ruuvi['Luftdruck'] = cut(raw.pressure/100,3);
ruuvi['RSSI'] = raw.rssi;
ruuvi['Batterie'] = cut(raw.batt/1000,3);
ruuvi['Counter'] = raw.cnt;
ruuvi['Update'] = full_time();
ruuvi['Ts'] = Shelly.getComponentStatus('sys').unixtime;
for (var key in ruuvi) {
if(key != 'Mac') {
components[ruuvi.Mac][key] = ruuvi[key];
}
}
if (components[ruuvi.Mac]['Alarm_cnt'] === undefined) {
components[ruuvi.Mac]['Alarm_cnt'] = ruuvi['Counter'];
components[ruuvi.Mac]['Alarm_ts'] = 0;
}
if (ruuvi['Counter'] > components[ruuvi.Mac]['Alarm_cnt']) {
components[ruuvi.Mac]['Alarm_cnt'] = ruuvi['Counter'];
components[ruuvi.Mac]['Alarm_ts'] = Shelly.getComponentStatus('sys').unixtime;
if(v.alarm_onoff) {
if(v.debug) print(components[ruuvi.Mac]['Name'] + ' !!! Alarm !!!');
alarm_ts = components[ruuvi.Mac]['Alarm_ts'];
alarm_name = components[ruuvi.Mac]['Name'];
alarm_time = full_time(components[ruuvi.Mac]['Alarm_ts']);
treat_http();
}
ruuvi = {};
}
} catch(e){print('ERROR in treat_data:', e.message)};
}
//Get time in hh:mm:ss
function full_time() {
date_now = Date(Shelly.getComponentStatus('sys').unixtime * 1000);
return time = ('0' + date_now.getHours()).substr(-2) + ':' + ('0' + date_now.getMinutes()).substr(-2)
+ ':' + ('0' + date_now.getSeconds()).substr(-2);
}
//Manipulate dynamic data
function treat_http() {
try {
html_data = '';
for(var each in components) {
let cl = '';
let since = '';
if(components[each].Ts != null) {
if(Shelly.getComponentStatus('sys').unixtime - components[each].Ts > v.not_seen) {
cl = 'blink'; since = 'seit ';
if (v.language === 'EN') since = 'since ';
}
} else cl = 'blink';
html_data += '<table>\n';
for(var key in components[each]) {
if(key != 'show' && includes(components[each]['show'], key)) {
if(key === 'Name') {
html_data += '\t<tr class="' + cl + '">\n\t\t<td colspan="3" style="text-align:center;">'
+ components[each][key] + ' '
+ since + components[each]['Update'] + '</td>\n\t</tr>\n';
}
else {
dat = String(components[each][key]);
if (typeof(components[each][key]) === 'number') {
if(dat.indexOf('.') === - 1) dat += '.00';
while(dat.length - dat.indexOf('.') < 3) {dat += '0'};
}
let unit = units[key];
html_data += '\t<tr>\n\t\t<td style="text-align:left;">' + key + '</td>\n\t\t<td style="text-align:right;">'
+ dat + '</td>\n\t\t<td style="text-align:right;">' + unit + '</td>\n\t</tr>\n';
}
}
}
let to_rep = '</br>wartet auf Daten';
if (v.language === 'EN') to_rep = '</br>waiting for data';
html_data = html_data.replace('undefined',to_rep) + '</table>\n';
if(v.language === 'EN') {
i=0;
for(var each in units) {
html_data = html_data.replace(each,translate[i]);
i++;
}
html_data = html_data.replace('<tr><td style="text-align:left;">Temp',
'<tr><td style="text-align:left;">Temperature');
}
}
cl = '';
let bg = v.al_off_color;
txt = 'Alarm ist ausgeschaltet';
if (v.alarm_onoff) {bg = v.al_on_color; txt = 'Alarm ist eingeschaltet';};
if (v.alarm_onoff && Shelly.getComponentStatus('sys').unixtime - alarm_ts < v.alarm_duration) {
bg = v.al_ongoing_color; txt = '!!! Alarm ist aktiv !!!';
cl = 'blink';
}
if(v.language === 'EN') {
txt=txt.replace('ist ausgeschaltet','is switched off');
txt=txt.replace('ist eingeschaltet','is switched on');
txt=txt.replace('ist aktiv','is active');
}
if (bg === v.al_off_color) {alarm_name = ''; alarm_time = '';};
let a_name = alarm_name;
if(alarm_name) {a_name = '</br>' + a_name; bg = v.al_ongoing_color;};
let alarm_link = '<table style="height:' + String(3 * v.font_size) + 'px;">\n'
+ '\t<tr>\n\t\t<td style="text-align:center;background-color:' + bg + ';"">'
+ '\n\t\t\t<a class="' + cl + '" id="alarm_link" style="text-decoration:none;display:block;color:'
+ v.font_color + ';"' + 'href="javascript:com(\'' + v.endpoint + '?switch_alarm\')">'
+ txt + ' ' + a_name + ' ' + alarm_time + '</a>\n\t\t</td>\n\t</tr>\n</table>';
html_data += alarm_link;
}catch(e){print('ERROR in treat_http:', e.message)};
}
//Responde to http_requets
function send_response(response, body) {
try {
response.code = 200;
response.body = body;
response.send();
}catch(e){print('ERROR in send_response:', e.message)};
}
//Get input from ws
function get_ws(ev) {
try {
//if(check_for_shelly(ev.info.data,'ws ','ws')) return;
if (ev.info.event === 'ruuvi.measurement') {
let device = ev.info.data.addr + ev.info.data.mac_5.toString(16);
if(device != undefined) {
if(components[device] === undefined) {
components[device] = {'Name':'XXX','show':['Temperatur','Luftfeuchtigkeit','Luftdruck','Batterie','Name','RSSI']};
get_file('config', null, 'components_write');
}
print('Device : ' + components[device]['Name']);
treat_data(ev.info.data, 'ws ');
}
}
}catch(e){print('ERROR in get_ws:', e.message)}
}
function get_file() {
//print(JSON.stringify(file_stack));
//print(file_stack.length);
if(file_stack.length === 0 || file_stack_busy) return;
file_stack_busy = true;
filename=file_stack[0][0];extra=file_stack[0][1];what=file_stack[0][2];
print(filename);
Shelly.call('Script.List','',
function(result, error_code, error_message){
let a = result['scripts'];
for (let i=0; i<a.length; i++) {
if(a[i]['name'] === filename) {
let para = {id:a[i]['id']};
Shelly.call('Script.GetCode', para,
function(result, error_code, error_message){
let sep = '//+++++++++++++++++++++++++++++++++++ ';
if(what === 'script') {
let aw=result.data.slice(result.data.indexOf(sep + 'script'),
result.data.indexOf(sep + 'script end'));
aw = aw.replace('*first','"' + first + '"').replace('*first','"' + first + '"');
send_response(extra, aw.replace('XXXXXX',v.endpoint)
.replace('YYYYYY',meld).replace(sep + 'script\n',''));
aw = '';
file_stack.splice(0,1);file_stack_busy = false; return;
}
if(what === '') {
print(JSON.stringify(v));
let aw=result.data.slice(result.data.indexOf(sep + 'html'),
result.data.indexOf(sep + 'html end'));
aw = aw.replace('<title>*endpoint','<title>' + v.endpoint.toUpperCase());
aw = aw.replace('*endpoint',v.endpoint).replace('*font_family',v.font_family).replace('*endpoint',v.endpoint);
aw = aw.replace('*font_size',v.font_size).replace('*font_family',v.font_family);
aw = aw.replace('*font_color',v.font_color).replace('*bg_color',v.bg_color).replace('*first',first);
aw = aw.replace('*font_weight',v.font_weight);
send_response(extra, aw.replace(sep + 'html\n',''));
aw = '';
file_stack.splice(0,1);file_stack_busy = false; return;
}
if(what.indexOf('components') > -1) {
let aw=result.data.slice(result.data.indexOf(sep + 'components'),
result.data.indexOf(sep + 'components end'));
aw = aw.replace(sep + 'components\n','');
if(what.indexOf('components_write') > -1) {
let c = '{\n';
for (var each in components) {
let n = each;
if(components[each]['Name']!='XXX') {
n=components[each]['Name'];
}else {
components[each]['Name']=String(each);
}
c = c + JSON.stringify(each) + ':{"Name":"' + n
+ '","show":["Temperatur","Luftfeuchtigkeit","Luftdruck","Batterie","Name","RSSI"]},\n';
}
c = c.slice(0,c.length - 2) + '\n}\n';
Shelly.call('Script.PutCode',
{id:i,code:result.data.replace(aw,c)});
aw = '';
file_stack.splice(0,1);file_stack_busy = false; return;
}
aw = JSON.parse(aw);
components = aw;
aw = '';
file_stack.splice(0,1);file_stack_busy = false; return;
}
if(what === 'v') {
let aw=result.data.slice(result.data.indexOf(sep + 'vars'),
result.data.indexOf(sep + 'vars end'));
aw = aw.replace(sep + 'vars\n','');
aw = JSON.parse(aw);
v = aw;
aw = '';
file_stack.splice(0,1);file_stack_busy = false; return;
}
});
;
}
}
}
);
}
//React on http
function get_http(request,response) {
try {
let query = String(request.query);
if(request.query === 'script') {
if(v.debug) print('Browser : ' + query);
file_stack.push(['config',response,query]);
//get_file('config', response, query);
}
if(request.query === 'switch_alarm') {
Timer.clear(t1);
if(v.debug) print('Browser : ' + query);
if(v.alarm_onoff===true) {
v.alarm_onoff = false;
} else {
v.alarm_onoff = true;
}
treat_http();
send_response(response, '');
t1= Timer.set(20000,true,treat_http);
}
if(request.query === '') {
if(v.debug) print('Browser : ' + 'html');
treat_http();
file_stack.push(['config',response,query]);
//get_file('config', response, query);
}
if(request.query === 'data') {
if(v.debug) print('Browser : ' + query);
send_response(response, html_data);
}
}catch(e){print('ERROR in get_http:', e.message)};
}
function main() {
//Do some user friendly printout
print('Your url is:');
print('http://' + Shelly.getComponentStatus("wifi").sta_ip + '/script/'
+ Shelly.getCurrentScriptId() + '/' + v.endpoint);
t1= Timer.set(20000,true,treat_http);
meld = '<div class=\\"blink\\">Alarm wird umgeschaltet</div>';
first = 'Warte auf Daten...';
if(v.language==='EN') {
meld = '<div class=\\"blink\\">Alarm will be toggled</div>';
first = 'Waiting for data...';
}
HTTPServer.registerEndpoint(v.endpoint,get_http);
Shelly.addEventHandler(get_ws);
}
//Some pre config
let units = {'Temperatur':'°C', 'Luftfeuchtigkeit':'%', 'Luftdruck':'hPa',
'Batterie':'V','RSSI':'dBm', 'Update':'', 'Name':'','Mac':''};
let translate = ['Temp','Humidity','Pressure','Battery','RSSI','Name','Mac'];
let html_data = '';
let alarm_ts = 0;
let alarm_name = '';
let alarm_time = '';
let components = {};
let v = {};
file_stack = [];
file_stack_busy = false;
let meld;
let first;
let t1;
let t2=Timer.set(500,true,get_file);
try {
file_stack.push(['config',null,'components']);
//get_file('config', null, 'components');
} catch(e){print('ERROR in config:', e.message)};
file_stack.push(['config', null, 'v']);
//while(v.endpoint === undefined){};
//get_file('config', null, 'v');
let delay = 2;
//print(Shelly.getComponentStatus('voltmeter:100').voltage);
if (Shelly.getComponentStatus('sys').uptime<10) delay=5;
Timer.set(delay * 1000,false,main);
Alles anzeigen
Non excutable config:
//+++++++++++++++++++++++++++++++++++ components
{
"f2:9f:86:22:d5:46":{"Name":"Bunker","show":["Temperatur","Luftfeuchtigkeit","Luftdruck","Batterie","Name","RSSI"]},
"c1:e3:4c:7a:27:b5":{"Name":"Briefkasten","show":["Temperatur","Luftfeuchtigkeit","Luftdruck","Batterie","Name","RSSI"]},
"c6:c5:22:e7:ab:7a":{"Name":"Reserve","show":["Temperatur","Luftfeuchtigkeit","Luftdruck","Batterie","Name","RSSI"]}
}
//+++++++++++++++++++++++++++++++++++ components end
//+++++++++++++++++++++++++++++++++++ vars
{
'endpoint' : 'ruuvi',
'alarm_onoff' : true,
'alarm_duration' : 30,
'language' : 'DE',
'not_seen' : 60,
'font_family' : 'monospace',
'font_size' : 40,
'font_weight' : 10,
'font_color' : '#FCFCFC',
'bg_color' : '#000000',
'al_ongoing_color' : '#9C071A',
'al_on_color' : '#228B22',
'al_off_color' : '#000000',
'debug' : true
}
//+++++++++++++++++++++++++++++++++++ vars end
//+++++++++++++++++++++++++++++++++++ script
function updateDiv() {
try{
if(index===true) return;
fetch("XXXXXX?data")
.then (
function(response) {
return response.text();
}
)
.then (
function(data) {
console.log(data);
if(data.indexOf("Not Found") > -1) data = old.replace("<table>","<table class = \"blink\">");
if(index===true) return;
if(data === '') data ="<div class=\"blink\">" + *first + "<div>";
document.getElementById("dataDiv").innerHTML=data;
old=data;
}
);
}catch(e){return;};
}
function com(command){
index = true;
console.log(command.split("?")[1]);
if(command.split("?")[1] === "switch_alarm") {
document.getElementById("alarm_link").innerHTML = "<div class=\"blink\">YYYYYY</div>";
}
fetch(command).then(function() {index = false;updateDiv();});
}
let index = false;
let old = "";
updateDiv();
setInterval(updateDiv, 10000);
//+++++++++++++++++++++++++++++++++++ script end
//+++++++++++++++++++++++++++++++++++ html
<!doctype html>
<html>
<head>
<title>*endpoint</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>
body {font-size:*font_sizepx;background-color:*bg_color;color:*font_color;font-weight:*font_weight;px;font-family:*font_family;}
tr {border:px;}
td {padding-right:10px;padding-left:10px;}
table {width:100%;border-radius:20px;border:5px solid #899499}
.blink {animation-name:animation_blink;animation-timing-function:ease-in;animation-duration:3s;animation-iteration-count:infinite;}
@keyframes animation_blink {0% { opacity: 1; }50% { opacity: 0.1; }100% { opacity: 1; }}
</style>
</head>
<body>
<div id="dataDiv"><div class="blink">*first</div></div>
<script type="application/javascript" src="*endpoint?script"></script>
</body>
</html>
//+++++++++++++++++++++++++++++++++++ html end
Alles anzeigen
Ihr seht, dass ist schon aufwändig 