[{"id":"39eb56aa.c614aa","type":"emoncms-server","server":"http://192.168.0.58/emoncms","name":"Locally Hosted Emoncms"},{"id":"ba386057.845d3","type":"mqtt-broker","broker":"192.168.0.58","port":"1883","clientid":""},{"id":"d7f98065.28068","type":"function","name":"fnBuildurl","func":"// The received message is stored in 'msg'\n// It will have at least a 'payload' property:\n\n// The 'context' object is available to store state\n// between invocations of the function\n// context = {};\n\n// The payload of the injected message contains the hostname and port\n// of the OSPI as csv's\n\n// global context variables are preset in settings.js\n// countresp is updated in fnProcesshttpresp\n// It is used to count the number of times through fnProcesshttpresponse\n// to ensure we have had as many responses as requests \n//Initialise it here\n// The first time through the number of responses will be 0\n\n// context.global.countstart and context.global.countresp are set to 0 in fn Set Global\n\n\n// check to see that the last http request was responded to\n// context.global.countresp is incremented while processing the response\n// so if it is not equal to context.countstart there was no response last time\n// doesn't apply first time through\nmsgo = msg;\n\n context.host=msg.payload.split(\",\");\n\n\nif (context.global.countstart > 0) {\n\n// As we have sent a request, then the no of responses should equal the number of requests\n\n if ((context.global.countstart == context.global.countresp) ) {\n\n// If it was responded to they will be equal. Send success diagnostic\n\n msgo.topic = \"Garden/OSPI/stationrun/api-response\";\n msgo.payload = \"Reached server - fnBuildurl \" ;\n msgo.payload = msgo.payload + context.global.countstart.toString() + ' ' + context.global.countresp.toString();\n }\n\n\n// First time through there was no previous response to have\n\n if ((context.global.countstart != context.global.countresp) ) {\n\n msgo.topic = \"Garden/OSPI/stationrun/api-response\";\n msgo.payload = \"Error reaching server - fnBuildurl \" ;\n// add some diagnostics\n msgo.payload = msgo.payload + context.global.countstart.toString() + ' ' + context.global.countresp.toString();\n \n// set them equal so next time the check will work\n\n context.global.countresp = context.global.countstart;\n }\n}\n//if first time get station names.\nif (context.global.countstart == 0) {\n\n// only do this the first time\n\n msgo.url = 'http://' + context.host[0] +':' + context.host[1] + '/jn?pw=' + context.host[2];\n// add some diagnostics\n msgo.payload = msgo.url+ \" Get Station names \";\n msgo.payload = msgo.payload + context.global.countstart.toString() + ' ' + context.global.countresp.toString();\n\n }\n\n//if second time get master valve number\n\nif (context.global.countstart == 1) {\n msgo.url = 'http://' + context.host[0] +':' + context.host[1] + '/jo?pw=' + context.host[2];\n msgo.payload = msgo.url+ \" Get Master Valve no \";\n msgo.payload = msgo.payload + context.global.countstart.toString() + ' ' + context.global.countresp.toString();\n\n }\n// All subsequent times just get station status\nif (context.global.countstart > 1) {\n msgo.url = 'http://' + context.host[0] +':' + context.host[1] + '/js?pw=' + context.host[2];\n msgo.payload = msgo.url+ \" Get Status \";\n msgo.payload = msgo.payload + context.global.countstart.toString() + ' ' + context.global.countresp.toString();\n\n}\ncontext.global.countstart = context.global.countstart + 1;\nreturn [msgo];","outputs":"1","x":163.04559326171875,"y":255.93939971923828,"z":"c3e73b60.3c18c8","wires":[["4b28d045.b4d73","2c641a61.d39be6"]]},{"id":"47b336b9.b84cc8","type":"inject","name":"Start","topic":"Garden/OSPI/stationrun/processing","payload":"192.168.0.182,8080,opendoor","payloadType":"string","repeat":"","crontab":"","once":false,"x":77.77275085449219,"y":47.11363220214844,"z":"c3e73b60.3c18c8","wires":[["a59bbed.f5a644"]]},{"id":"4b28d045.b4d73","type":"debug","name":"fn Build URL","active":true,"console":"false","complete":"false","x":538.1591339111328,"y":253.74998474121094,"z":"c3e73b60.3c18c8","wires":[]},{"id":"d24cc8ef.2db338","type":"debug","name":"Http Request","active":false,"console":"false","complete":"false","x":538.4545135498047,"y":284.25001525878906,"z":"c3e73b60.3c18c8","wires":[]},{"id":"3a62be14.c59d42","type":"function","name":"fnProcesshttpresponse","func":"// Messages returned \n// - Station start\n// - station stops (duration is in payload, station number in topic)\n// - errors\n\n// First response processed is from OSPi (to /jn?pw=... - get station names\n// - we must save station names\n// First save the msg (including payload) so we can build a new one\n// without wrecking the old one\n\n// This function just produces MQTT messages - Other flows will subscribe to these messages and send them to \n// XBMC, Emoncms or wherever. This allows a more modular approach\n\n// MQTT topics produced by this function are \n// Garden/OSPI/stationrun/api-noresponse\n// Garden/OSPI/stationrun/start/\n// Garden/OSPI/stationrun/stop/\n\n// For start and stop the station number is in the payload\n \nomsg = msg;\ntopic = msg.topic;\nstatusCode = msg.statusCode;\n\n\nif (statusCode != 200 ) {\n\n// This error processing does not handle the case when there is no response from OSPI\n\n// Still need to get the first two headers, so retry \n\n// will add more error processing. For now just return and try again\n// the error message will go to MQTT\n\n msg.topic = \"Garden/OSPI/stationrun/api-response\";\n msg.payload = \"Error reaching server - code \" + statusCode;\n\n return [omsg];\n} \n\n// set up a date object with now as the date/time\ntempdate = new Date() ;\n\n//\n//----------------------------------------------\n// check if this is the first succesful time through\n//----------------------------------------------\n\nif ( context.global.countresp == 0) {\n\ncontext.snames = [\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\"]; // Initialise\ncontext.starttime = [ 0, 0, 0, 0, 0, 0, 0, 0 ];\ncontext.lastsn = [\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"];\n for (i=0;i<8;i++) {\n \n context.snames[i] = omsg.payload.snames[i];\n\n// set up start times and status (sn). Initially set status to off (0). \n// These are global so this function so will persist \n\n context.starttime[i] = new Date();\n context.lastsn[i] = 0;\n context.global.countresp = 1;\n \n }\n\n// Don't want output at this stage - next time we will get more information from OSPi \n\n return [null];\n }\n//\n//----------------------------------------\n// Second time through\n// ---------------------------------------\n//\n//response (to /jo?pw=.. - get options\n\nif (context.global.countresp == 1) {\n\n// - save Master station number (mas) (0 means none)\n// stations are 0 - 7, mas is 1-8. Subtract 1 from mas \n\n context.mas = msg.payload.mas -1;\n context.noofstns = 8 + msg.payload.ext * 8;\n\n// Don't want ouput at this stage - next time we will start getting station status data from OSPi \n return [null];\n }\n//\n//-------------------------------------\n// All subsequent times through (Must be > 1)\n//--------------------------------------\n//\n\nif (context.global.countresp > 1) {\n\n// Subsequent responses (to /js?pw=...\n// - process the station status. \n// If a station is on check if it has just been turned on\n// and it is not the master\n// If this is true\n// - save the start time (per station as it may not be in sequential mode), \n// - and construct a message for MQTT saying \"Station xxxxxx started\"\n//\n// If a station is off check if it has just been turned off\n// If it has\n// - calculate the duration in milliseconds\n// - construct a payload for EMoncms which has the station and duration\n// This version only caters for one station turning on at a time (a todo item)\n// context.noofstns = omsg.payload.nstations;\n\nfor (i=0;i<8;i++) {\n//omsg.payload = omsg.payload + \" \" + omsg.payload.sn[5] + \" \" +context.lastsn[5] + \" \" +context.mas;\n//return omsg;\n \n if ((omsg.payload.sn[i] == 1) && (context.lastsn[i] == 0) && (i != context.mas)) {\n\n// Save station status and time it started\n\n context.lastsn[i] = omsg.payload.sn[i];\n context.starttime[i] = tempdate;\n\n// send MQTT message that will get sent to the TV\n\n omsg.topic = 'Garden/OSPI/stationrun/start';\n omsg.payload = \"Station - \"+ i.toString() +context.snames[i] + \" started at \" + context.starttime[i].toString();\n context.global.countresp = context.global.countresp + 1;\n return[omsg];\n }\n if ((omsg.payload.sn[i] == 0) && (context.lastsn[i] == 1) && (i != context.mas)) {\n context.lastsn[i] = omsg.payload.sn[i];\n duration = Math.abs(tempdate-context.starttime[i]);\n \n omsg.topic = 'Garden/OSPI/stationrun/stop';\n \n// in the payload the / will be used to split the payload at the duration \n\n omsg.payload = \"Station - \"+ i.toString() + \" /\" + duration.toString() + \"/\";\n// add some debug information\n omsg.payload = omsg.payload + \" \" + tempdate.toString() + \" \" + context.starttime[i].toString();\n context.global.countresp = context.global.countresp + 1;\n \n return [omsg];\n\n }\n\n// If we get here it is not an error, or start or stop\n// increment context.global.countresp so fnBuildurl will know we got a response\n\ncontext.global.countresp = context.global.countresp + 1;\n\n// Save the current status and time\n\n context.starttime[i] = tempdate;\n context.lastsn[i] = omsg.payload.sn[i];\n\n }\n}\nreturn [null];\n","outputs":"1","x":296.9501037597656,"y":347.20008277893066,"z":"c3e73b60.3c18c8","wires":[["76f8f02f.89071","b74328be.48bcd8"]]},{"id":"76f8f02f.89071","type":"debug","name":"Errors,start,stop","active":true,"console":"true","complete":"true","x":544.7000885009766,"y":374.9500274658203,"z":"c3e73b60.3c18c8","wires":[]},{"id":"1da70e4a.e258f2","type":"debug","name":"Json out","active":false,"console":"false","complete":"true","x":523.7000274658203,"y":314.9500274658203,"z":"c3e73b60.3c18c8","wires":[]},{"id":"8d7cea09.728318","type":"json","name":"Json ","x":221.25012969970703,"y":317.000039100647,"z":"c3e73b60.3c18c8","wires":[["1da70e4a.e258f2","3a62be14.c59d42"]]},{"id":"2c641a61.d39be6","type":"http request","name":"http request","method":"GET","url":"","x":202.70008087158203,"y":285.9500207901001,"z":"c3e73b60.3c18c8","wires":[["d24cc8ef.2db338","8d7cea09.728318"]]},{"id":"b74328be.48bcd8","type":"mqtt out","name":"Output from processing status ","topic":"","qos":"0","retain":"false","broker":"ba386057.845d3","x":587.9499664306641,"y":344.9500274658203,"z":"c3e73b60.3c18c8","wires":[]},{"id":"25ad1419.da52ec","type":"mqtt in","name":"Returns/errors from API calls","topic":"Garden/OSPI/stationrun/api-response","broker":"ba386057.845d3","x":120,"y":490.1999969482422,"z":"c3e73b60.3c18c8","wires":[["74a6653d.8b599c","6ce3076d.931cf8"]]},{"id":"74a6653d.8b599c","type":"function","name":"fnSendtoXBMC","func":"var paylmqtt = msg.payload;\nvar topicstr = msg.topic;\n// This is a lvl 2 topic\noutmsg = msg;\npayloadmqtto = '\"{\"lvl\":\"2\",\"sub\":\"';\npayloadmqtto = payloadmqtto + topicstr + '\",';\npayloadmqtto = payloadmqtto + '\"txt\":\"'+paylmqtt+'\",\"img\":\"/home/pi/.xbmc/userdata/Thumbnails/background.png\",\"delay\": \"20000\"}';\noutmsg.payload = payloadmqtto;\noutmsg.topic = \"Home/xbmc1\";\nreturn [outmsg];","outputs":1,"x":370.2000274658203,"y":492.45001792907715,"z":"c3e73b60.3c18c8","wires":[["4767e15b.b8982","2ed02f35.d12fd"]]},{"id":"4767e15b.b8982","type":"mqtt out","name":"Send errors to XBMC","topic":"Home/ospi","qos":"0","retain":"false","broker":"ba386057.845d3","x":653.7000846862793,"y":492.44996643066406,"z":"c3e73b60.3c18c8","wires":[]},{"id":"ea53ba2c.15ac48","type":"mqtt in","name":"Station stop messages","topic":"Garden/OSPI/stationrun/stop","broker":"ba386057.845d3","x":137.59285736083984,"y":444.05715560913086,"z":"c3e73b60.3c18c8","wires":[["e27d1f82.1d82e","6f0e8ea6.90f17"]]},{"id":"e27d1f82.1d82e","type":"function","name":"fnSendtoEmoncms","func":"paylmqtt = msg.payload;\ntopicstr = msg.topic;\npaylmqtto = \" fnSendtoEmoncms\";\nsubtopics = [\" \",\" \",\" \",\" \"];\n// Emoncms is expecting a payload like [0,0,0,78,0,0,0,0] \n// where this means a duration of 78 seconds for station 3\n\n// The station number is in the payload \n\n// The topic is of the form\n// Garden/OSPI/stationrun/start\n// or\n// Garden/OSPI/stationrun/stop\n\n//Only Stop messages go to Emoncms\n\n// Get the station number\nsubtopics = msg.payload.split(' ');\nsn = subtopics[2];\n\n// I am sure this can be done better\n\n var spl = [0,0,0,0,0,0,0,0];\n// The / was put in payload so the duration could be found\n splitpayload = paylmqtt.split('/');\n\n duration = splitpayload[1];\n\n spl[sn] = duration;\n paylmqtto = \"[\"+spl[0]+\",\"+spl[1]+\",\"+spl[2]+\",\"+spl[3]+\",\"+spl[4]+\",\"+spl[5]+\",\"+spl[6]+\",\"+spl[7]+\"]\";\n msg.payload = paylmqtto;\n return [msg];\n\n","outputs":1,"x":378.45005798339844,"y":462.95001792907715,"z":"c3e73b60.3c18c8","wires":[["bdb27557.424d88","3da80bf.fc257f4"]]},{"id":"bdb27557.424d88","type":"emoncms","name":"Emoncms","emonServer":"39eb56aa.c614aa","nodegroup":"25","x":618.9501457214355,"y":463.9499969482422,"z":"c3e73b60.3c18c8","wires":[]},{"id":"7d982275.8267dc","type":"mqtt in","name":"Station start messages","topic":"Garden/OSPI/stationrun/start","broker":"ba386057.845d3","x":137.09284210205078,"y":534.4856872558594,"z":"c3e73b60.3c18c8","wires":[["f37c342e.0c83c8","14aae646.eb551a"]]},{"id":"f37c342e.0c83c8","type":"function","name":"fnSendtoXBMC","func":"var paylmqtt = msg.payload;\nvar topicstr = msg.topic;\n// This is a lvl 1 topic\noutmsg = msg;\n\noutmsg.topic = \"Home/xbmc1\";\npayloadmqtto = '{\"lvl\":\"2\",\"sub\":';\npayloadmqtto = payloadmqtto + '\"' + topicstr + '\",';\npayloadmqtto = payloadmqtto + '\"txt\":\"'+paylmqtt+'\",\"img\":\"/home/pi/.xbmc/userdata/Thumbnails/background.png\",\"delay\": \"20000\"}';\noutmsg.payload = payloadmqtto;\nreturn [outmsg];","outputs":1,"x":371.2000198364258,"y":521.200023651123,"z":"c3e73b60.3c18c8","wires":[["c9005a4e.36ffa8","2ed02f35.d12fd"]]},{"id":"c9005a4e.36ffa8","type":"mqtt out","name":"Send start messages to XBMC","topic":"Home/ospi","qos":"0","retain":"false","broker":"ba386057.845d3","x":680.4500846862793,"y":523.1999969482422,"z":"c3e73b60.3c18c8","wires":[]},{"id":"6ce3076d.931cf8","type":"debug","name":"Errors from API","active":true,"console":"false","complete":"true","x":371.2000274658203,"y":552.1999969482422,"z":"c3e73b60.3c18c8","wires":[]},{"id":"6f0e8ea6.90f17","type":"debug","name":"Stop messages","active":true,"console":"false","complete":"true","x":368.7000274658203,"y":433.20001792907715,"z":"c3e73b60.3c18c8","wires":[]},{"id":"14aae646.eb551a","type":"debug","name":"Stat Start messages","active":true,"console":"false","complete":"true","x":384.9500274658203,"y":582.7000122070312,"z":"c3e73b60.3c18c8","wires":[]},{"id":"2ed02f35.d12fd","type":"debug","name":"sent to xbmc","active":true,"console":"false","complete":"payload","x":625.7000846862793,"y":583.6999969482422,"z":"c3e73b60.3c18c8","wires":[]},{"id":"b7319d2e.48ce6","type":"inject","name":"Toggle on/off","topic":"Garden/OSPI/stationrun/processing","payload":"192.168.0.182,8080,opendoor","payloadType":"string","repeat":"","crontab":"","once":false,"x":93.74999237060547,"y":76.99999237060547,"z":"c3e73b60.3c18c8","wires":[["1d95ac5f.e26a54","e05f89e5.1fa078"]]},{"id":"1d95ac5f.e26a54","type":"function","name":"Set loop Global","func":"\n\nif (context.global.state == 'off' ) {\n\tcontext.global.state = 'on';\n\n} else {\n\tcontext.global.state = 'off';\n\treturn null;\n}\n\nreturn msg;","outputs":1,"x":253.75003051757812,"y":80.0000228881836,"z":"c3e73b60.3c18c8","wires":[["bb897ba1.447688"]]},{"id":"bb897ba1.447688","type":"function","name":"Control Loop","func":"// The received message is stored in 'msg'\n// It will have at least a 'payload' property:\n// console.log(msg.payload);\n// The 'context' object is available to store state\n// between invocations of the function\n// context = {};\n\nif (context.global.state == 'off' ) {\n\tmsg.loop = 'off';\n} else {\n\tmsg.loop = 'on';\n}\n\nreturn msg;","outputs":1,"x":443.52783203125,"y":47.833343505859375,"z":"c3e73b60.3c18c8","wires":[["1628a645.e9d75a"]]},{"id":"1628a645.e9d75a","type":"delay","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":588.3611450195312,"y":47.83334732055664,"z":"c3e73b60.3c18c8","wires":[["b172480a.4e8db8"]]},{"id":"b172480a.4e8db8","type":"function","name":"Loop","func":"// The received message is stored in 'msg'\n// It will have at least a 'payload' property:\n// console.log(msg.payload);\n// The 'context' object is available to store state\n// between invocations of the function\n// context = {};\nconsole.log('Entering loop');\nconsole.log(msg.loop);\nmsg.payload = context.global.saveparams;\nif (msg.loop == 'off' ) {\n\treturn [msg,null];\n} else {\n\tconsole.log('Looping');\n\treturn [msg,msg];\n}","outputs":"2","x":499.9444580078125,"y":129.02779388427734,"z":"c3e73b60.3c18c8","wires":[["bb897ba1.447688"],["d7f98065.28068"]]},{"id":"e05f89e5.1fa078","type":"debug","name":"","active":true,"console":"false","complete":"true","x":228.75003051757812,"y":110.5,"z":"c3e73b60.3c18c8","wires":[]},{"id":"3da80bf.fc257f4","type":"debug","name":"Send to Emoncms","active":true,"console":"false","complete":"payload","x":643.1110954284668,"y":552.7777557373047,"z":"c3e73b60.3c18c8","wires":[]},{"id":"a59bbed.f5a644","type":"function","name":"fnSetappGlobal","func":"context.global.countstart = 0;\ncontext.global.countresp = 0;\ncontext.global.saveparams = msg.payload;\nreturn msg;","outputs":1,"x":255.77780151367188,"y":47.888885498046875,"z":"c3e73b60.3c18c8","wires":[["bb897ba1.447688"]]},{"id":"1e0dc7d9.e1f238","type":"comment","name":"Control","info":"This section enables you to start and stop/reset the process.\n\nUseful for debugging. Start/reset counters to 0 by clicking on Start. \nThen click on Toggle on/off to start it, and pause it. \n\nConfigure Start and Toggle with the host,port,password (of OSPI). These should \nbe comma separated. (I haven't worked out configuration nodes yet!).\n\nAdjust the timing by changing the delay. 5 seconds works well for debugging.\n\nI have added debug messages to the message payload. For example if you see 15 15 \nthis is the count of the no of requests to OSPI, and the number of responses.\n\nWhen count = 0 the first request for station names is sent.\nWhen count = 1 the second request for master station number is sent\nWhen count > 1 requests for valve status are sent. Once this is happening \nyou can start and stop sprinklers and the start and stop will be processed. \n\nWhen debugging you can then pause the process and inspect the debug output \nat your leisure.\n\nWhen debugging, putting a return [msg]; statement in a function effectively \ncreates a breakpoint of sorts. Useful for tracking down runtime errors that \njavascript won't say where they are! eg \"index of undefined\". \n\nIn production a separate start node should be added that fires off at a set interval. \nThis is so that it will not require someone to click on the start and toggle buttons every time\nnode-red restarts.\n\nTip for the future.\nInstead of adding debug information to the msg body, I will add it to a new message property.\neg instead of adding variable xyz to the message body, I would add it to msg.xyz\ncontext.xyz would be added to msg.cxyz and global.context.xyz would be added to msg.gcxyz\nAdditional text could be added as well. \n\nAcknowledgement:\nThis looping functionality came from \nhttps://www.ibm.com/developerworks/community/blogs/hickmat/entry/updated_version_of_node_red_loop?lang=en\n\n\n\n\n \n","x":78.19999694824219,"y":20,"z":"c3e73b60.3c18c8","wires":[]},{"id":"155d2723.eaa2d9","type":"comment","name":"Main processing","info":"The production start inject node must be changed to inject the string \nevery x seconds. This node will then automatically fire whenever node-red restarts\nand continue firing. For testing this node is turned off. The control loop can be left \nin place as it will do nothing if not clicked. \n\nHere a http://host:port/jn?pw=password is sent to get the station names\nThen http://host:port/jo?pw=password is sent to get the master valve no\nThen repeated http://host:port/js?password messages are sent to get the valve status's\n\nThese are monitored for changes for starts and stops. \nStarts are sent to XBMC via MQTT and the start time noted\nStops are sent to Emoncms via MQTT after calculating the duration.\nErrors in communication with OSPI (no response or return code ne 200)\nare sent to XBMC via MQTT\n\nThe process is \nBuild the URL\nSend the HTTP request\nPut the response through the JSON Node \n (I have no idea what this does but the next function crashes if I dont).\nProcess the response.\n\nThis main processing section results in MQTT messages only. It does not\nsend messages directly to the end recipients eg XBMC).","x":120,"y":174.1999969482422,"z":"c3e73b60.3c18c8","wires":[]},{"id":"eb9e2e17.1461d","type":"comment","name":"Process results","info":"Here the MQTT messages that are sent from the main processing are subscribed to, \nreformatted for the appropriate recipient, and sent off.\n\nTo add eg an email message whenever a station starts, simply add another\nflow, subscribing to the start message, create a function to reformat the message \nfor email and pass the message to the email node. Same for twitter etc.\n","x":113.9142837524414,"y":402.48572731018066,"z":"c3e73b60.3c18c8","wires":[]},{"id":"1ed2ed83.e12d12","type":"comment","name":"Debug nodes","info":"These can be removed, but this simply would make the flow look simpler. \n\nI have used separate debug nodes instead of one common one so that the debug node name \nhelps identify where the debug message comes from.","x":101.19999694824219,"y":599.2000122070312,"z":"c3e73b60.3c18c8","wires":[]},{"id":"2d4434ba.d2bbcc","type":"inject","name":"Production start","topic":"","payload":"host,port,password","payloadType":"string","repeat":"","crontab":"","once":false,"x":117,"y":205.1999969482422,"z":"c3e73b60.3c18c8","wires":[["d7f98065.28068"]]},{"id":"36f4bc28.c90b44","type":"comment","name":"Deployment","info":"To modiify these flows for another site, the inject nodes must all be \neditted so the string injected is host,port,password of your system. \nHost is the OSPI host.\n\nThe MQTT nodes must be editted to set the address of the MQTT broker.\nThis is only done once as they all share the same configuration node.\nSame for the Emoncms node.\n\nTo use the XBMC notifications, see https://github.com/matbor/mqtt2xbmc-notifications\nYou will need to edit autoexec.py to subscribe to the correct MQTT topic\n\nAll that is required to implement it on an XBMC system is to place \nautoexec.py and mosquitto.py in the /home/pi/.xbmc/userdata directory.\n\nThe topics I have used may need to be modified for your needs. Unfortunately\nthese topics are spread all over the place. In future perhaps a set of globals \nmay be useful so that this configuration can be done in one function.\n\n","x":101.71427917480469,"y":633.1428632736206,"z":"c3e73b60.3c18c8","wires":[]}]