Skip to content

Commit

Permalink
universal accessory (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
hobbyquaker committed Oct 19, 2018
1 parent 385371a commit 38ede51
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 1 deletion.
111 changes: 111 additions & 0 deletions nodes/redmatic-homekit-universal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<script type="text/javascript">
RED.nodes.registerType('redmatic-homekit-universal', {
category: 'redmatic homekit',
defaults: {
bridgeConfig: {value: 'CC:22:3D:E3:CE:C7:51826', type: 'redmatic-homekit-bridge', required: true},
name: {required: true},
services: {value: []}
},
inputs: 1,
outputs: 1,
icon: 'homekit2.png',
color: '#E2D96E',
paletteLabel: 'Universal',
align: 'left',
label() {
return 'Universal' || this.name;
},
labelStyle() {
return this.name ? 'node_label_italic' : '';
},
oneditprepare() {
const availableServices = ['AirPurifier','AirQualitySensor','BatteryService','CarbonDioxideSensor','CarbonMonoxideSensor','ContactSensor','Door','Doorbell','Fan','Fanv2','Faucet','FilterMaintenance','GarageDoorOpener','HeaterCooler','HumidifierDehumidifier','HumiditySensor','IrrigationSystem','LeakSensor','LightSensor','Lightbulb','LockManagement','LockMechanism','Microphone','MotionSensor','OccupancySensor','Outlet','SecuritySystem','Slat','SmokeSensor','Speaker','StatelessProgrammableSwitch','Switch','TemperatureSensor','Thermostat','Valve','Window','WindowCovering'];

$('ol#services').editableList({
removable: true,
addItem: function(row, index, data) {
let html = '<span class="subtype">' + index + '</span>';
html += '<select class="service">';
availableServices.forEach(s => {
const selected = s === data.service ? ' selected' : '';
html += '<option' + selected + '>' + s + '</option>';
});
html += '</select>';
html += '<input class="name" value="' + (data.name || '') + '">';
$(row).html(html);

},
removeItem: function (data) {
const services = [];
let subtype = 0;
const items = $('ol#services').editableList('items');
items.each(function () {
services.push({
subtype: subtype++,
service: $(this).find('.service').val(),
name: $(this).find('.name').val()
});
});
$('ol#services').editableList('empty');
$('ol#services').editableList('addItems', services);
}
});

$('ol#services').editableList('addItems', this.services);
},
oneditsave() {
const items = $('ol#services').editableList('items');
const services = [];
items.each(function () {
services.push({
subtype: $(this).find('.subtype').html(),
service: $(this).find('.service').val(),
name: $(this).find('.name').val()
});
});
this.services = services;
}
});
</script>

<script type="text/x-red" data-template-name="redmatic-homekit-universal">

<div class="form-row">
<label for="node-input-bridgeConfig"><i class="icon-globe"></i> Bridge</label>
<input type="text" id="node-input-bridgeConfig">
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-globe"></i> Name</label>
<input type="text" id="node-input-name">
</div>
<style>
span.subtype {
padding-left: 3px;
padding-right: 6px;
}
input.name {
width: calc(100% - 260px);
background-color: #ffffff;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
height: 30px;
margin-left: 6px;
padding-left: 6px;
font-size: 14px;
line-height: 20px;
color: #555555;
vertical-align: middle;
border-radius: 4px;
}
</style>
<div class="form-row">
<ol id="services">
</ol>
</div>


</script>

<script type="text/x-red" data-help-name="redmatic-homekit-universal">

</script>
90 changes: 90 additions & 0 deletions nodes/redmatic-homekit-universal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
module.exports = function (RED) {
class RedMaticHomeKitUniversal {
constructor(config) {
RED.nodes.createNode(this, config);

this.bridgeConfig = RED.nodes.getNode(config.bridgeConfig);

if (!this.bridgeConfig) {
return;
}

const {hap} = this.bridgeConfig;

this.name = config.name || ('Universal ' + this.id);
this.services = config.services || [];

const acc = this.bridgeConfig.accessory({id: this.id, name: this.name});

if (!acc.isConfigured) {
acc.getService(hap.Service.AccessoryInformation)
.setCharacteristic(hap.Characteristic.Manufacturer, 'RedMatic')
.setCharacteristic(hap.Characteristic.Model, 'Universal')
.setCharacteristic(hap.Characteristic.SerialNumber, this.id)
.setCharacteristic(hap.Characteristic.FirmwareRevision, '0');

this.services.forEach(s => {
this.debug('addService ' + s.subtype + ' ' + s.service + ' ' + s.name);
acc.addService(hap.Service[s.service], s.name, s.subtype);
});

acc.isConfigured = true;
}

this.listeners = [];

this.services.forEach(s => {
acc.getService(s.subtype).characteristics.forEach(c => {

const cName = c.displayName.replace(/ /g, '')

this.debug('create change listener', s.subtype, cName);

const changeListener = obj => {
const topic = s.subtype + '/' + cName;
console.log('hap ->', topic, obj.newValue);
if (obj && obj.context && obj.context.request) {
this.send({
topic,
payload: obj.newValue
});
}
};

this.listeners.push({subtype: s.subtype, characteristic: c, listener: changeListener, cName})

c.on('change', changeListener);
});
});

this.on('input', msg => {
const [subtype, c] = msg.topic.split('/');
const service = acc.getService(subtype);
if (service) {
if (service.testCharacteristic(hap.Characteristic[c])) {
if (typeof msg.payload === 'object') {
this.debug('setProps ' + msg.topic + ' ' + JSON.stringify(msg.payload));
service.getCharacteristic(hap.Characteristic[c]).setProps(msg.payload);
} else {
this.debug('-> hap ' + msg.topic + ' ' + msg.payload);
service.updateCharacteristic(hap.Characteristic[c], msg.payload);
}
} else {
this.error('unknown characteristic ' + c + ' on subtype ' + subtype);
}
} else {
this.error('unknown subtype ' + subtype);
}
});

this.on('close', () => {
this.listeners.forEach(l => {
this.debug('remove change listener ' + l.subtype + ' ' + l.cName);
l.characteristic.removeListener('change', l.listener);
});
});
}
}

RED.nodes.registerType('redmatic-homekit-universal', RedMaticHomeKitUniversal);
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"redmatic-homekit-bridge": "nodes/redmatic-homekit-bridge.js",
"redmatic-homekit-homematic-devices": "nodes/redmatic-homekit-homematic-devices.js",
"redmatic-homekit-switch": "nodes/redmatic-homekit-switch.js",
"redmatic-homekit-statelessprogrammableswitch": "nodes/redmatic-homekit-statelessprogrammableswitch.js"
"redmatic-homekit-statelessprogrammableswitch": "nodes/redmatic-homekit-statelessprogrammableswitch.js",
"redmatic-homekit-universal": "nodes/redmatic-homekit-universal.js"
}
},
"dependencies": {
Expand Down

0 comments on commit 38ede51

Please sign in to comment.