// Parameters which depend on the system: const myserialpath = '/dev/ttyUSB1' // Parameters to finetune: const timebetweencmd = 1 // ms const timebetweenrefresh = 10000 // ms const path = require('path'); var { SerialPort, ReadlineParser } = require('serialport') //const port = new SerialPort('/dev/ttyUSB1', { baudRate: 57600, path: 'blub'}) const port = new SerialPort({path: myserialpath, baudRate: 19200 }, function (err) { if (err) { return console.log('Error opening port: ', err.message) } }) //const parser = new ReadlineParser() //port.pipe(parser) //parser.on('data', console.log) //port.write('ROBOT PLEASE RESPOND\n') var commands = [ "setADM(2)f", // change to admin mode - answer is FACTORY "getSRN", // get serial number - 8 alphanumeric digits "getVER", // get product name aka Safe-T+ V2.00e "get71", // ?? 0 returned "getAB", // Valve status: 1=open 2=closed "getALA", // ?? alarm? FF returned "getALM", // ?? Returns: Alarms: A6 A3 A5 A9 A3 A9 A5 ->A9 "getAVO", // volume drawn since last opening in ml "getBAR", // get current water pressure "getBAT", // Get current battery voltage. Reply is in Volt: 6,12 4,38 3,90 - only first value matters. Others: ?? "getBSI", // 2 (16bar) - allowable pressure? "getCEL", // returns water temperature in °C * 10 "getCNO", // get product key "getDMA", // ?? 2 returned "getDOM", // ?? 3 min returned "getDRP", // ?? 1 returned "getLE", // Limit if present in multiple of 50l "getNPS", // ?? Number is constantly increasing "getT1", // ?? returns 2 // time leackage set to multiple of 30min "getT2", // ?? returns 1 "getTBS", // ?? returns 1 "getTC", // ?? returns 30 "getTMP", // disable leackage detection for x seconds "getTO", // ?? returns 30 "getTYP", // ?? returns 1 "getUL", // state 0 is present, larger than 0 is limit in liter while away "getUNI", // ?? returns 0 "getVLV", // ?? returns 20 "getVOL", // total volume drawn in l "clrADM" // Returns ADMIN RESET ]; var lastmessage='none'; var lastsend = -1; var numbercommands = commands.length; var allcreated = 0; function forcesetState(objectname, value, options) { //console.log("Setting object " + objectname + " to " + value); if(allcreated == 0) { if(!existsState(objectname)) { createState(objectname, value, options); } else { setStateAsync(objectname, value); } } else { setStateAsync(objectname, value); } } function parsedata(message, data) { if(lastmessage.includes("clrADM")) return; // nothing to do. var varname = message.substr(3); var mydata = data; var unit = ""; // special handling: if(varname =="AVO") { mydata = parseInt(mydata); unit = "mL" } else if (varname =="BAR") { mydata = parseInt(mydata) / 1000; unit = "bar" } else if (varname =="T1") { varname = "TimeLeackage" mydata = parseInt(mydata) * 30; unit = "min" } else if (varname =="VOL") { varname = "Total_Water_usage" mydata = data.substr(6); mydata = parseInt(mydata); unit = "l" } else if (varname =="CEL") { varname = "Water_temperature" mydata = parseInt(mydata) / 10; unit = "°C" } else if (varname =="DOM") { mydata = parseInt(mydata); unit = "min" } else if (varname =="DOM") { mydata = data.substr(7); mydata = parseInt(mydata); unit = "l" } else if (varname =="BAT") { varname = "Battery_voltage" mydata = data.substr(0,4).replace(',','.'); mydata = parseFloat(mydata); unit = "V"; } else if (varname =="LE") { varname = "Limit_Presence" mydata = parseInt(mydata) * 50; unit = "L" } else if (varname =="ALA") { mydata = parseInt(mydata, 16); } else if (varname =="TMP") { varname = "Leackage_disabling_timer" mydata = parseInt(mydata); unit = "s" } else if (varname =="UL") { mydata = parseInt(mydata); if(mydata == 0) { varname = "Presence_state" mydata = true; forcesetState("Watersupply.SYR_T_Connect." + varname, mydata, {name: "", unit: unit}); varname = "Limit_Away" mydata = 0; unit = "l" } else { varname = "Presence_state" mydata = false; forcesetState("Watersupply.SYR_T_Connect." + varname, mydata, {name: "", unit: unit}); varname = "Limit_Away" mydata = parseInt(data) * 10; unit = "l" } } else if (varname =="AB") { varname = "Valve_open" if(data == "1") mydata = true; else if (data == "2") mydata = false else { console.warn("Unknown value for valve status! " + data); } } forcesetState("Watersupply.SYR_T_Connect." + varname, mydata, {name: "", unit: unit}); } function processinput(data) { if(lastsend == -1) return; if(data.toLowerCase().includes("error")) { // Abort transmission in case of an error message. lastsend = -1; return; } if(data.toLowerCase().includes("setADM")) { // Note: sometimes the network chip does request the device type - which overlaps the communication and leads to wrong messages. lastsend = -1; return; } if((data.toLowerCase().includes("get") || data.toLowerCase().includes("set") || data.toLowerCase().includes("clr") ) && !data.toLowerCase().includes("reset")) { console.debug("Got a strange reply from SYR T-connect: " + data + " - aborting data requests."); lastsend = -1; } else { parsedata(lastmessage, data); //console.log("Command " + lastmessage + " resulted in reply " + data); lastsend++; if(lastsend < numbercommands) { var cmdstart = Buffer.from('0D0A1B313A', 'hex'); var cmdmiddle = Buffer.from(commands[lastsend]); var cmdend = Buffer.from('0D0A', 'hex'); var cmdarray = [cmdstart, cmdmiddle, cmdend]; var fullcommand = Buffer.concat(cmdarray); setTimeout(() => port.write(fullcommand, function(err) { if (err) { return console.log('Error on write: ', err.message) } else { lastmessage = commands[lastsend]; } }), timebetweencmd); } else { lastsend = -1; allcreated = 1; } } } const parser = new ReadlineParser({ delimiter: '\r' }) port.pipe(parser) parser.on('data', data => processinput(data)); setInterval(function() { if (lastsend != -1) { console.debug("Last transmission not completed in time!"); } var cmdstart = Buffer.from('0D0A1B313A', 'hex'); var cmdmiddle = Buffer.from(commands[0]); var cmdend = Buffer.from('0D0A', 'hex'); var cmdarray = [cmdstart, cmdmiddle, cmdend]; var fullcommand = Buffer.concat(cmdarray); setTimeout(() => port.write(fullcommand, function(err) { if (err) { return console.log('Error on write: ', err.message) } lastmessage='clrADM' lastsend = 0; }), 0); }, timebetweenrefresh); // Open errors will be emitted as an error event port.on('error', function(err) { console.log('Error: ', err.message) })