mirror of
				https://github.com/karl0ss/orvibo-b25-server-kex.git
				synced 2025-11-04 08:30:59 +00:00 
			
		
		
		
	Inital commit of Orvibo socket server code
This commit is contained in:
		
							parent
							
								
									196493e7e2
								
							
						
					
					
						commit
						4ad59b2a46
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
.idea/
 | 
			
		||||
node_modules
 | 
			
		||||
							
								
								
									
										64
									
								
								Example.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Example.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
const Orvibo = require('./Orvibo');
 | 
			
		||||
const http = require('http');
 | 
			
		||||
const url = require('url');
 | 
			
		||||
 | 
			
		||||
const httpPort = 3000;
 | 
			
		||||
 | 
			
		||||
let orvbio = new Orvibo();
 | 
			
		||||
 | 
			
		||||
// When a socket first connects and initiates the handshake it will emit the connected event with the uid of the socket;
 | 
			
		||||
orvbio.on('plugConnected', ({uid, name}) => {
 | 
			
		||||
    console.log(`Connected ${uid} name = ${name}`);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// If the socket state is updated this event will fire
 | 
			
		||||
orvbio.on('plugStateUpdated', ({uid, state , name}) => {
 | 
			
		||||
    console.log(`Plug ${name} ${uid} updated state ${state}`);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// The plug sends a hearbeat to let the server know it's still alive
 | 
			
		||||
orvbio.on('gotHeartbeat', ({uid, state , name}) => {
 | 
			
		||||
    console.log(`Plug ${name} ${uid} sent heartbeat`);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Called when the plug disconnects
 | 
			
		||||
orvbio.on('plugDisconnected', ({uid, name }) => {
 | 
			
		||||
    console.log(`Plug ${uid} - ${name} disconnected`);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Called when the plug disconnects with an error ie it's been unplugged
 | 
			
		||||
orvbio.on('plugDisconnectedWithError', ({uid, name }) => {
 | 
			
		||||
    console.log(`Plug ${uid} - ${name} disconnected with error`);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Start the Orvibo socket server
 | 
			
		||||
orvbio.startServer();
 | 
			
		||||
 | 
			
		||||
// Create a basic example HTTP server
 | 
			
		||||
// If there are no parameters it will return the uid, state, modelId and name of the socket
 | 
			
		||||
// You can then use the uid to toggle the state of the switch like
 | 
			
		||||
// http://localhost:3000?uid=5dcf7ff76e7a
 | 
			
		||||
 | 
			
		||||
const requestHandler = (request, response) => {
 | 
			
		||||
    response.writeHead(200, {'Content-Type': 'application/json'});
 | 
			
		||||
    let q = url.parse(request.url, true).query;
 | 
			
		||||
    if (q.uid != null) {
 | 
			
		||||
        orvbio.toggleSocket(q.uid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get all currently connected sockets, their names and states
 | 
			
		||||
    let sockets = orvbio.getConnectedSocket();
 | 
			
		||||
 | 
			
		||||
    response.end(JSON.stringify(sockets));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const httpServer = http.createServer(requestHandler)
 | 
			
		||||
 | 
			
		||||
httpServer.listen(httpPort, (err) => {
 | 
			
		||||
    if (err) {
 | 
			
		||||
        return console.log('something bad happened', err)
 | 
			
		||||
    }
 | 
			
		||||
    console.log(`http server is listening on ${httpPort}`)
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										226
									
								
								Orvibo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								Orvibo.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,226 @@
 | 
			
		||||
const net = require('net');
 | 
			
		||||
const util = require('util');
 | 
			
		||||
const Packet = require('./OrviboPacket');
 | 
			
		||||
const PacketBuilder = require('./PacketBuilder');
 | 
			
		||||
const Utils = require('./Utils');
 | 
			
		||||
const Settings = require('./OrviboSettings');
 | 
			
		||||
const EventEmitter = require('events').EventEmitter;
 | 
			
		||||
 | 
			
		||||
const ORVIBO_KEY = Settings.ORVIBO_KEY;
 | 
			
		||||
const LOG_PACKET = Settings.LOG_PACKET;
 | 
			
		||||
 | 
			
		||||
if (ORVIBO_KEY === '') {
 | 
			
		||||
    console.log('Please add Orvibo PK key to OrviboSettings.js file. See Readme');
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Orvibo = function() {};
 | 
			
		||||
 | 
			
		||||
Object.assign(Orvibo.prototype, EventEmitter.prototype);
 | 
			
		||||
 | 
			
		||||
let HEARTBEAT = 32;
 | 
			
		||||
let HELLO = 0;
 | 
			
		||||
let HANDSHAKE = 6;
 | 
			
		||||
let STATE_UPDATE = 42;
 | 
			
		||||
let STATE_UPDATE_CONFIRM = 15;
 | 
			
		||||
let UNKNOWN_CMD = 'UNKNOWN_CMD';
 | 
			
		||||
 | 
			
		||||
let port = 10001;
 | 
			
		||||
let bindHost = '0.0.0.0';
 | 
			
		||||
 | 
			
		||||
console.log(`Starting server Orvibo socket server on port ${port}`);
 | 
			
		||||
 | 
			
		||||
let plugConnections = [];
 | 
			
		||||
let packetData = {};
 | 
			
		||||
 | 
			
		||||
// Put your smart socket data here and it will be matched to the uid
 | 
			
		||||
let plugInfo = Settings.plugInfo;
 | 
			
		||||
 | 
			
		||||
let getNameForUid = (uid) => {
 | 
			
		||||
    let item = plugInfo.find(item => item.uid === uid);
 | 
			
		||||
    return item != null ? item.name : 'unknown';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let getData = (id) => {
 | 
			
		||||
    return packetData[id];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let setData = (id, data) => {
 | 
			
		||||
    packetData[id] = data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let respondAndSetData = (data, socket, packetFunction) => {
 | 
			
		||||
    setData(socket.id, data);
 | 
			
		||||
    socket.write(packetFunction(data));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let helloHandler = (plugPacket, socket) => {
 | 
			
		||||
    let pkData = {
 | 
			
		||||
        serial: plugPacket.getSerial(),
 | 
			
		||||
        encryptionKey: Utils.generateRandomTextValue(16),
 | 
			
		||||
        id: Utils.generateRandomHexValue(32),
 | 
			
		||||
        modelId: plugPacket.getModelId(),
 | 
			
		||||
    };
 | 
			
		||||
    respondAndSetData(pkData, socket, PacketBuilder.helloPacket);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let handshakeHandler = function(plugPacket, socket, socketData) {
 | 
			
		||||
    let uid = plugPacket.getUid();
 | 
			
		||||
    let pkData = Object.assign({}, socketData, {
 | 
			
		||||
        serial: plugPacket.getSerial(),
 | 
			
		||||
        uid,
 | 
			
		||||
        name: getNameForUid(uid)
 | 
			
		||||
    });
 | 
			
		||||
    respondAndSetData(pkData, socket, PacketBuilder.handshakePacket);
 | 
			
		||||
    this.emit('plugConnected', {uid:pkData.uid, name: pkData.name});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let heartbeatHandler = function(plugPacket, socket, socketData) {
 | 
			
		||||
    let pkData = Object.assign({}, socketData, {
 | 
			
		||||
        serial: plugPacket.getSerial(),
 | 
			
		||||
        uid: plugPacket.getUid()
 | 
			
		||||
    });
 | 
			
		||||
    respondAndSetData(pkData, socket, PacketBuilder.heartbeatPacket);
 | 
			
		||||
    this.emit('gotHeartbeat', {uid:pkData.uid, name: pkData.name});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let stateUpdateHandler = function(plugPacket, socket, socketData) {
 | 
			
		||||
    let pkData = Object.assign({}, socketData, {
 | 
			
		||||
        serial: plugPacket.getSerial(),
 | 
			
		||||
        uid: plugPacket.getUid(),
 | 
			
		||||
        state: plugPacket.getValue1()
 | 
			
		||||
    });
 | 
			
		||||
    respondAndSetData(pkData, socket, PacketBuilder.comfirmStatePacket);
 | 
			
		||||
    this.emit('plugStateUpdated', {uid:pkData.uid, state: pkData.state, name: pkData.name});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let stateConfirmHandler = function() {
 | 
			
		||||
    // Do nothing at this stage
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let unknownCmdHandler = function(plugPacket, socket, socketData) {
 | 
			
		||||
    let pkData = Object.assign({}, socketData, {
 | 
			
		||||
        serial: plugPacket.getSerial(),
 | 
			
		||||
        uid: plugPacket.getUid(),
 | 
			
		||||
    });
 | 
			
		||||
    respondAndSetData(pkData, socket, PacketBuilder.defaultPacket);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Orvibo.prototype.handlers = function() {
 | 
			
		||||
    return {
 | 
			
		||||
        [HELLO]: helloHandler.bind(this),
 | 
			
		||||
        [HANDSHAKE]: handshakeHandler.bind(this),
 | 
			
		||||
        [HEARTBEAT]: heartbeatHandler.bind(this),
 | 
			
		||||
        [STATE_UPDATE]: stateUpdateHandler.bind(this),
 | 
			
		||||
        [STATE_UPDATE_CONFIRM] : stateConfirmHandler,
 | 
			
		||||
        [UNKNOWN_CMD]: unknownCmdHandler.bind(this)
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Orvibo.prototype.startServer = function() {
 | 
			
		||||
 | 
			
		||||
    let self = this;
 | 
			
		||||
 | 
			
		||||
    let handlers = this.handlers();
 | 
			
		||||
 | 
			
		||||
    this.server = net.createServer(function(socket) {
 | 
			
		||||
 | 
			
		||||
        socket.id = Utils.generateRandomTextValue(16);
 | 
			
		||||
        socket.setKeepAlive(true, 10000);
 | 
			
		||||
        plugConnections.push(socket);
 | 
			
		||||
 | 
			
		||||
        socket.on('data', function (data) {
 | 
			
		||||
 | 
			
		||||
            let socketData = getData(socket.id);
 | 
			
		||||
            let plugPacket = new Packet(data);
 | 
			
		||||
 | 
			
		||||
            if (!plugPacket.validCRC()) {
 | 
			
		||||
                console.log('Got invalid CRC');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (plugPacket.packetTypeText() === 'pk') {
 | 
			
		||||
                plugPacket.processPacket(ORVIBO_KEY);
 | 
			
		||||
            } else {
 | 
			
		||||
                plugPacket.processPacket(socketData.encryptionKey);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            LOG_PACKET && plugPacket.logPacket("Socket -> ");
 | 
			
		||||
 | 
			
		||||
            let handler = handlers[plugPacket.getCommand()];
 | 
			
		||||
            if (handler != null) {
 | 
			
		||||
                handler(plugPacket, socket, socketData);
 | 
			
		||||
            } else {
 | 
			
		||||
                handlers[UNKNOWN_CMD](plugPacket, socket, socketData);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        socket.on('end', function () {
 | 
			
		||||
            let pkData = getData(socket.id);
 | 
			
		||||
            self.emit('plugDisconnected', {uid: pkData.uid, name: pkData.name});
 | 
			
		||||
            delete packetData[socket.id];
 | 
			
		||||
            plugConnections.splice(plugConnections.indexOf(socket), 1);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        socket.on('error', (err) => {
 | 
			
		||||
            console.log(err);
 | 
			
		||||
            console.log('error with socket ' + socket.id);
 | 
			
		||||
            self.emit('plugDisconnectedWithError', getData(socket.id));
 | 
			
		||||
            delete packetData[socket.id];
 | 
			
		||||
            plugConnections.splice(plugConnections.indexOf(socket), 1);
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.server.listen(port, bindHost);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Orvibo.prototype.toggleSocket = function(uid) {
 | 
			
		||||
 | 
			
		||||
    let socketId = null;
 | 
			
		||||
    for (const key of Object.keys(packetData)) {
 | 
			
		||||
        if (packetData[key].uid === uid) {
 | 
			
		||||
            socketId = key;
 | 
			
		||||
            break
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (socketId === null) {
 | 
			
		||||
        console.log('Could not find socket ' + uid);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    let socket = plugConnections.find(s => s.id === socketId);
 | 
			
		||||
    if (socket != null) {
 | 
			
		||||
        let socketData = getData(socketId);
 | 
			
		||||
        let data = Object.assign({}, socketData,{
 | 
			
		||||
            state: socketData.state === 1 ? 0 : 1,
 | 
			
		||||
            serial: Utils.generateRandomNumber(8),
 | 
			
		||||
            clientSessionId:  socketData.clientSessionId ? socketData.clientSessionId : Utils.generateRandomHexValue(32),
 | 
			
		||||
            deviceId: socketData.deviceId ? socketData.deviceId : Utils.generateRandomHexValue(32),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        setData(socket.id, data);
 | 
			
		||||
 | 
			
		||||
        let packet = PacketBuilder.updatePacket(data);
 | 
			
		||||
        socket.write(packet);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        console.log('Can not find socket ');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Orvibo.prototype.getConnectedSocket = function() {
 | 
			
		||||
    let sockets = [];
 | 
			
		||||
    for (const key of Object.keys(packetData)) {
 | 
			
		||||
        let socketData = getData(key);
 | 
			
		||||
        sockets.push({
 | 
			
		||||
            name: socketData.name,
 | 
			
		||||
            state: socketData.state,
 | 
			
		||||
            uid: socketData.uid,
 | 
			
		||||
            modelId: socketData.modelId
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    return sockets;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = Orvibo;
 | 
			
		||||
							
								
								
									
										71
									
								
								OrviboPacket.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								OrviboPacket.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
const crc32 = require('buffer-crc32');
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
 | 
			
		||||
let pkt = function(packetBuffer) {
 | 
			
		||||
    this.magic = packetBuffer.slice(0,2);
 | 
			
		||||
    this.packetLength = packetBuffer.slice(2,4);
 | 
			
		||||
    this.packetType = packetBuffer.slice(4,6);
 | 
			
		||||
    this.crc32 = packetBuffer.slice(6,10);
 | 
			
		||||
    this.packetId = packetBuffer.slice(10,42);
 | 
			
		||||
    this.payload = packetBuffer.slice(42, packetBuffer.length);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.logPacket = function(type) {
 | 
			
		||||
    let output = {
 | 
			
		||||
        PacketId : this.packetIdText(),
 | 
			
		||||
        Payload : this.payloadJSON
 | 
			
		||||
    };
 | 
			
		||||
    console.log(type, JSON.stringify(this.payloadJSON));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.getCommand = function() {
 | 
			
		||||
    return this.payloadJSON.cmd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.getSerial = function() {
 | 
			
		||||
    return this.payloadJSON.serial;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.getUid = function() {
 | 
			
		||||
    return this.payloadJSON.uid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.getValue1 = function() {
 | 
			
		||||
    return this.payloadJSON.value1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.getModelId = function() {
 | 
			
		||||
    return this.payloadJSON.modelId;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.processPacket = function(key) {
 | 
			
		||||
    this.payloadJSON = this.decodeJSON(key);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.getKeyValue = function() {
 | 
			
		||||
    return this.payloadJSON.key;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.validCRC = function() {
 | 
			
		||||
    return crc32(this.payload).toString('hex') === this.crc32.toString('hex');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.packetTypeText = function() {
 | 
			
		||||
    return this.packetType.toString('ascii');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.packetIdText = function() {
 | 
			
		||||
    return this.packetId.toString('ascii');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pkt.prototype.decodeJSON = function(key) {
 | 
			
		||||
    let decipher = crypto.createDecipheriv('aes-128-ecb', key, '');
 | 
			
		||||
    decipher.setAutoPadding(true);
 | 
			
		||||
    let decrypted = decipher.update(this.payload.toString('hex'), 'hex', 'utf8');
 | 
			
		||||
    decrypted += decipher.final('utf8');
 | 
			
		||||
    // Sometimes there are bad chars on the end of the JSON so check here
 | 
			
		||||
    decrypted = decrypted.substring(0, decrypted.indexOf('}') + 1);
 | 
			
		||||
    return JSON.parse(decrypted);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = pkt;
 | 
			
		||||
							
								
								
									
										13
									
								
								OrviboSettings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								OrviboSettings.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
// Settings/Config store for orvibo socket server
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    LOG_PACKET: false,
 | 
			
		||||
    ORVIBO_KEY: '', // put your PK key here as plain text
 | 
			
		||||
    plugInfo : [
 | 
			
		||||
        // Add uid and a name so you can easily identify the connected sockets
 | 
			
		||||
        {
 | 
			
		||||
            uid :'53dd7fe74de7',
 | 
			
		||||
            name: "Lamp in Kitchen"
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										182
									
								
								PacketBuilder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								PacketBuilder.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
			
		||||
const crc32 = require('buffer-crc32');
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
const Settings = require('./orviboSettings');
 | 
			
		||||
 | 
			
		||||
const ORVIBO_KEY = Settings.ORVIBO_KEY;
 | 
			
		||||
 | 
			
		||||
let Packet = {
 | 
			
		||||
    encryptionKey : ORVIBO_KEY,
 | 
			
		||||
    magic: new Buffer("6864", 'hex'),
 | 
			
		||||
    build: function () {
 | 
			
		||||
        let packetId = new Buffer(this.id, 'ascii');
 | 
			
		||||
        let payload = encodePayload(JSON.stringify(this.json), this.encryptionKey);
 | 
			
		||||
        let crc = crc32(payload);
 | 
			
		||||
        let length = getLength([this.magic, this.packetType, packetId, crc, payload], 2); // Extra 2 for the length field itself
 | 
			
		||||
        return Buffer.concat([this.magic, length, this.packetType, crc, packetId, payload]);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let PKPacket = Object.assign({}, Packet, {
 | 
			
		||||
    packetType: new Buffer('pk', 'ascii'),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
let DKPacket = Object.assign({}, Packet, {
 | 
			
		||||
    packetType: new Buffer('dk', 'ascii'),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
let helloPacket = function({ serial, encryptionKey, id }) {
 | 
			
		||||
    let json = {
 | 
			
		||||
        cmd: 0,
 | 
			
		||||
        status: 0,
 | 
			
		||||
        serial: serial,
 | 
			
		||||
        key: encryptionKey
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pkt = Object.assign(Object.create(PKPacket), {
 | 
			
		||||
        json: json,
 | 
			
		||||
        id: id
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return pkt.build();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let handshakePacket = function({ serial, encryptionKey, id }) {
 | 
			
		||||
 | 
			
		||||
    let json = {
 | 
			
		||||
        cmd: 6,
 | 
			
		||||
        status:0,
 | 
			
		||||
        serial: serial
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pkt = Object.assign(Object.create(DKPacket), {
 | 
			
		||||
        json: json,
 | 
			
		||||
        id: id,
 | 
			
		||||
        encryptionKey, encryptionKey
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return pkt.build();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let heartbeatPacket = function({serial, uid, encryptionKey, id}) {
 | 
			
		||||
    let json = {
 | 
			
		||||
        cmd: 32,
 | 
			
		||||
        status:0,
 | 
			
		||||
        serial: serial,
 | 
			
		||||
        uid: uid,
 | 
			
		||||
        utc: new Date().getTime()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pkt = Object.assign(Object.create(DKPacket), {
 | 
			
		||||
        json: json,
 | 
			
		||||
        id: id,
 | 
			
		||||
        encryptionKey, encryptionKey
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return pkt.build();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let comfirmStatePacket = function({serial, uid, state, encryptionKey, id}) {
 | 
			
		||||
 | 
			
		||||
    var json = {
 | 
			
		||||
        uid: uid,
 | 
			
		||||
        cmd: 42,
 | 
			
		||||
        statusType: 0,
 | 
			
		||||
        value3: 0,
 | 
			
		||||
        alarmType: 1,
 | 
			
		||||
        serial: serial,
 | 
			
		||||
        value4: 0,
 | 
			
		||||
        deviceId: 0,
 | 
			
		||||
        value1: state,
 | 
			
		||||
        value2: 0,
 | 
			
		||||
        updateTimeSec: new Date().getTime(),
 | 
			
		||||
        status: 0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pkt = Object.assign(Object.create(DKPacket), {
 | 
			
		||||
        json: json,
 | 
			
		||||
        id: id,
 | 
			
		||||
        encryptionKey, encryptionKey
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return pkt.build();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let defaultPacket = function({serial, uid, cmd, id, encryptionKey}) {
 | 
			
		||||
 | 
			
		||||
    let json = {
 | 
			
		||||
        uid: uid,
 | 
			
		||||
        cmd: cmd,
 | 
			
		||||
        serial: serial,
 | 
			
		||||
        status: 0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pkt = Object.assign(Object.create(DKPacket), {
 | 
			
		||||
        json: json,
 | 
			
		||||
        id: id,
 | 
			
		||||
        encryptionKey, encryptionKey
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return pkt.build();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
let updatePacket = function({ uid, state, serial, id, clientSessionId , deviceId, encryptionKey}) {
 | 
			
		||||
    let json = {
 | 
			
		||||
        uid: uid,
 | 
			
		||||
        delayTime: 0,
 | 
			
		||||
        cmd: 15,
 | 
			
		||||
        order: state === 0 ? "on" : "off",
 | 
			
		||||
        userName: "iloveorvibo@orvibo.com",
 | 
			
		||||
        ver: "3.0.0",
 | 
			
		||||
        value3: 0,
 | 
			
		||||
        serial: serial,
 | 
			
		||||
        value4: 0,
 | 
			
		||||
        deviceId: deviceId,
 | 
			
		||||
        value1: state,
 | 
			
		||||
        value2: 0,
 | 
			
		||||
        clientSessionId: clientSessionId
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pkt = Object.assign(Object.create(DKPacket), {
 | 
			
		||||
        json: json,
 | 
			
		||||
        id: id,
 | 
			
		||||
        encryptionKey, encryptionKey
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return pkt.build();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
let encodePayload = function(json, key) {
 | 
			
		||||
    let cipher = crypto.createCipheriv('aes-128-ecb', key, '');
 | 
			
		||||
    cipher.setAutoPadding(true);
 | 
			
		||||
    let crypted = cipher.update(json,'utf8','hex');
 | 
			
		||||
    crypted += cipher.final('hex');
 | 
			
		||||
    return new Buffer(crypted, 'hex');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let getLength = function(items, extra) {
 | 
			
		||||
    let length = extra || 0;
 | 
			
		||||
    for (let i = 0; i < items.length; i++) {
 | 
			
		||||
        length += items[i].length;
 | 
			
		||||
    }
 | 
			
		||||
    return getHexLengthPadded(length);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let getHexLengthPadded = function(lengthDecimal) {
 | 
			
		||||
    let lengthHex = lengthDecimal.toString(16);
 | 
			
		||||
    let paddingLength = 4 - lengthHex.length;
 | 
			
		||||
    let padding = '';
 | 
			
		||||
    for (let i = 0; i < paddingLength; i++) {
 | 
			
		||||
        padding +=0;
 | 
			
		||||
    }
 | 
			
		||||
    return new Buffer(padding + lengthHex, 'hex');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports.helloPacket = helloPacket;
 | 
			
		||||
module.exports.handshakePacket = handshakePacket;
 | 
			
		||||
module.exports.heartbeatPacket = heartbeatPacket;
 | 
			
		||||
module.exports.comfirmStatePacket = comfirmStatePacket;
 | 
			
		||||
module.exports.defaultPacket = defaultPacket;
 | 
			
		||||
module.exports.updatePacket = updatePacket;
 | 
			
		||||
@ -16,10 +16,7 @@ You will need to add the Orvibo PK key to decrypt and encrypt the initial packet
 | 
			
		||||
Once you have this key you will need to add it the ``OrviboSettings.js`` file.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Because these new sockets don't use UDP packets to communicate like the older versions you will also need to redirect all traffic from the host name 
 | 
			
		||||
```
 | 
			
		||||
homemate.orvibo.com
 | 
			
		||||
```
 | 
			
		||||
Because these new sockets don't use UDP packets to communicate like the older versions you will also need to redirect all traffic from the host name ``homemate.orvibo.com``
 | 
			
		||||
on TCP port 10001 the computer running the server.
 | 
			
		||||
 | 
			
		||||
I used an Ubuntu machine running dnsmasq and set this server as my DNS server in my router but depending on your network you might have to do it differntly.
 | 
			
		||||
@ -37,7 +34,6 @@ to the official Orvibo server.
 | 
			
		||||
Clone the repo and then run
 | 
			
		||||
```
 | 
			
		||||
npm install 
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
to install the dependencies (buffer-crc32)
 | 
			
		||||
 | 
			
		||||
@ -50,7 +46,6 @@ To start the example http server run
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
npm start 
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
This will start the Orvibo socket server create a basic example HTTP server used for interacting with sockets.
 | 
			
		||||
Calling this http server with no parameters will return the uid, state, modelId and name of the socket.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								Utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Utils.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
module.exports.generateRandomTextValue = function(length) {
 | 
			
		||||
    let chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 | 
			
		||||
    let result = '';
 | 
			
		||||
    for (let i = length; i > 0; --i) {
 | 
			
		||||
        result += chars[Math.floor(Math.random() * chars.length)];
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.generateRandomHexValue = function(length) {
 | 
			
		||||
    let chars = '0123456789abcdef';
 | 
			
		||||
    let result = '';
 | 
			
		||||
    for (let i = length; i > 0; --i) {
 | 
			
		||||
        result += chars[Math.floor(Math.random() * chars.length)];
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.generateRandomNumber = function(length) {
 | 
			
		||||
    let numbers = '0123456789';
 | 
			
		||||
    let result = '';
 | 
			
		||||
    for (let i = length; i > 0; --i) {
 | 
			
		||||
        result += numbers[Math.floor(Math.random() * numbers.length)];
 | 
			
		||||
    }
 | 
			
		||||
    return parseInt(result);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "orvibo-b25-server",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "lockfileVersion": 1,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "buffer-crc32": {
 | 
			
		||||
      "version": "0.2.13",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
 | 
			
		||||
      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "orvibo-b25-server",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "A server to control the Orvibo B25 range of smart sockets",
 | 
			
		||||
  "main": "Orvibo.js",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "echo \"Error: no test specified\" && exit 1",
 | 
			
		||||
    "start": "node Example.js"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://github.com/sandysound/orvibo-b25-server.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "Orvibo",
 | 
			
		||||
    "B25",
 | 
			
		||||
    "Smart",
 | 
			
		||||
    "Socket"
 | 
			
		||||
  ],
 | 
			
		||||
  "author": "Sandy Milne",
 | 
			
		||||
  "license": "Apache-2.0",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/sandysound/orvibo-b25-server/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://github.com/sandysound/orvibo-b25-server#readme",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "buffer-crc32": "^0.2.13"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user