Last active
August 26, 2017 01:33
-
-
Save enishoca/4a1df399e62147b148105989c937a118 to your computer and use it in GitHub Desktop.
Mochad listener for sending X-10 commands to SmartThings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* X10toSTsignals.js -- | |
* | |
* Copyright (C) 2017 Enis Hoca | |
* | |
* This software may be modified and distributed under the terms | |
* of the MIT license. | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
var inject = require('reconnect-core'); | |
var net = require('net'); | |
var events = require("events"); | |
const request = require('request'); | |
var hostname = 'pi'; // host name or IP address of mochad server | |
var port = 1099; // mochad port - default 1099 | |
// Modify the section below and map x10 commands to REST calls for Smartthing devices | |
var event = new events.EventEmitter(); | |
event.on("data", function (eventData) { | |
var command = eventData.housecode + eventData.unitcode + "-" + eventData.state; | |
console.log("data: " + command); | |
var stUrl=""; | |
switch (command) { | |
case "c1-on": //X-10 switch | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
break; | |
case "c1-off": | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/off?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
break; | |
case "0xfe*-arm_home_min_sh624": //X-10 Security Device | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
break; | |
case "0xfe*-disarm_sh624": | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/off?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
break; | |
case "c8-on": //multiple X-10 devices controlling multiple SmartThings device | |
case "b8-on": | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); //Kitchen | |
break; | |
case "c8-off": //House | |
case "b8-off": | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/off?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/off?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999on?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); | |
stUrl = "https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/88888888-9999-8888-9999-999999999999/switches/88888888-9999-8888-9999-999999999999/off?access_token=88888888-9999-8888-9999-999999999999"; | |
callurl(stUrl); //Kitchen | |
break; | |
case "ss-on": //One X-10 device controlling another | |
stUrl = "RF A3 ON"; | |
mochadConnection.write(stUrl + "\r\n"); | |
break; | |
case "s-off": | |
stUrl = "RF A3 OFF"; | |
mochadConnection.write(stUrl + "\r\n"); | |
break; | |
} | |
}); | |
// No need to modify anything below this | |
var mochadConnection = null; | |
var lastCodeSeen = { | |
housecode: "x", | |
unitcode: "0" | |
}; | |
var reconnect = inject(function () { | |
return net.connect.apply(null, arguments); | |
}); | |
var re = reconnect({ | |
initialDelay: 1e3, | |
setKeepAlive: true, | |
maxDelay: 10e3, | |
strategy: 'fibonacci', // available: fibonacci, exponential | |
failAfter: Infinity, | |
randomisationFactor: 0, | |
immediate: false, | |
}, function (stream) { | |
stream.on('data', function (data) { | |
var lines; | |
lines = data.toString(); | |
console.log(lines); | |
return parseReceivedCmd(lines); | |
}); | |
}) | |
.on('connect', function (con) { | |
console.log("(Re)Opened connection"); | |
mochadConnection = con; | |
}) | |
.on('disconnect', function (err) { | |
console.log(("Disconnected from " + hostname + ":" + port + ": ") + err); | |
mochadConnection = null; | |
}) | |
.on('error', function (err) { | |
// never forget | |
console.log("Connection Error " + err); | |
}) | |
.connect(port, hostname); | |
function callurl(url) { | |
console.log('stUrl:', url); | |
if (!url) { | |
return; | |
} | |
request( url, function (error, response, body) { | |
console.log('error:', error); | |
console.log('statusCode:', response && response.statusCode); | |
console.log('body:', body); | |
}); | |
} | |
function parseReceivedCmd(lines) { | |
var eventData, m; | |
// Parsing all-units-on/off | |
// example: 05/22 00:34:04 Rx PL House: P Func: All units on | |
// example: 05/22 00:34:04 Rx PL House: P Func: All units off | |
if (m = /^\d{2}\/\d{2}\s+(?:\d{2}:){2}\d{2}\s(Rx|Tx)\s+(RF|PL)\s+House:\s+([a-pA-P])\s+Func:\s+All\s+(units|lights)\s+(on|off)$/m.exec(lines)) { | |
eventData = { | |
protocol: m[2].toLowerCase(), | |
direction: m[1].toLowerCase(), | |
housecode: m[3].toLowerCase(), | |
unitcode: "*" + m[4], | |
state: m[5].toLowerCase() | |
}; | |
event.emit("data", eventData); | |
} | |
// Parsing security remotes / sensors | |
// example: 07/04 02:07:52 Rx RFSEC Addr: 0xFE Func: Lights_On_SH624 | |
// example: 07/04 02:46:46 07/04 02:46:47 Rx RFSEC Addr: 0xFE Func: Arm_Home_min_SH624 | |
// example: 07/04 02:46:46 07/04 02:46:48 Rx RFSEC Addr: 0xFE Func: Disarm_SH624 | |
// example: 07/04 02:46:46 07/04 02:46:49 Rx RFSEC Addr: 0xFE Func: Arm_Away_min_SH624 | |
// example: 07/04 02:46:46 07/04 02:46:50 Rx RFSEC Addr: 0xFE Func: Disarm_SH624 | |
// example: 07/04 02:46:46 07/04 02:46:51 Rx RFSEC Addr: 0xFE Func: Lights_On_SH624 | |
// example: 07/04 02:46:46 07/04 02:46:52 Rx RFSEC Addr: 0xFE Func: Lights_Off_SH624 | |
if (m = /^\d{2}\/\d{2}\s+(?:\d{2}:){2}\d{2}\s(Rx|Tx)\s+(RFSEC)\s+Addr:\s+(0x[0-9a-fA-F]+)(\s+)Func:\s+(.+)$/m.exec(lines)) { | |
eventData = { | |
protocol: m[2].toLowerCase(), | |
direction: m[1].toLowerCase(), | |
housecode: m[3].toLowerCase(), | |
unitcode: "*" + m[4].trim(), | |
state: m[5].toLowerCase() | |
}; | |
event.emit("data", eventData); | |
} | |
// Parsing simple on/off (RF-style) | |
// example: 11/30 17:57:12 Tx RF HouseUnit: A10 Func: On | |
// example: 11/30 17:57:24 Tx RF HouseUnit: A10 Func: Off | |
if (m = /^\d{2}\/\d{2}\s+(?:\d{2}:){2}\d{2}\s(Rx|Tx)\s+(RF|PL)\s+HouseUnit:\s+([a-pA-P])(\d{1,2})\s+Func:\s+(On|Off)/m.exec(lines)) { | |
eventData = { | |
protocol: m[2].toLowerCase(), | |
direction: m[1].toLowerCase(), | |
housecode: m[3].toLowerCase(), | |
unitcode: parseInt(m[4], 10), | |
state: m[5].toLowerCase() | |
}; | |
event.emit("data", eventData); | |
} | |
//Parsing simple on/off (PL-style) | |
// example: 05/30 20:59:20 Tx PL HouseUnit: P1 | |
//example: 05/30 20:59:20 Tx PL House: P Func: On | |
//example2: 09/01 23:42:03 Tx PL HouseUnit: P1 | |
//example2: 09/01 23:42:03 Tx PL House: P Func: On | |
else if (m = /^\d{2}\/\d{2}\s+(?:\d{2}:){2}\d{2}\s(?:Rx|Tx)\s+(?:RF|PL)\s+HouseUnit:\s+([a-pA-P])(\d{1,2})/m.exec(lines)) { | |
lastCodeSeen.housecode = m[1].toLowerCase(); | |
lastCodeSeen.unitcode = parseInt(m[2], 10); | |
} | |
if (lastCodeSeen.housecode && lastCodeSeen.unitcode && (m = /\d{2}\/\d{2}\s+(?:\d{2}:){2}\d{2}\s(Rx|Tx)\s+(RF|PL)\s+House:\s+([a-pA-P])\s+Func:\s+(On|Off)$/m.exec(lines))) { | |
Data = { | |
protocol: m[2].toLowerCase(), | |
direction: m[1].toLowerCase(), | |
housecode: m[3].toLowerCase(), | |
unitcode: null, // filled later | |
state: m[4].toLowerCase() | |
}; | |
if (eventData.housecode === lastCodeSeen.housecode) { | |
eventData.unitcode = lastCodeSeen.unitcode; | |
event.emit("data", eventData); | |
} | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment