Skip to content

Adding a Device Type Capability

coldfire84 edited this page Apr 12, 2019 · 17 revisions

This Section Needs Refreshing

Following release of GHome API this section is due an overhaul. Alexa guidance is correct however Google Home/ Assistant guidance needs documenting.

  • An example API/ Web Interface commit to add a new Alexa sensor capability can be viewed here.
  • An example Node-RED contrib commit to add a new Alexa sensor capability can be viewed here.

State Data Model

Consider what state object the device will store, see devices.js model for information on current state elements, at time of writing this is as-is:

// attributes : {
//     colorModel: String,
//     colorTemperatureRange: {
//         temperatureMinK: Number,
//         temperatureMaxK: Number
//     },
//     contact: String,
//     temperatureRange: {
//         temperatureMin: Number,
//         temperatureMax: Number,    
//     },
//     temperatureScale: String,
//     thermostatModes: [],
//     availableModes: Schema.Types.Mixed,
//     availableToggles: Schema.Types.Mixed,
//     availableFanSpeeds: Schema.Types.Mixed,
//     sceneReversible: Boolean,
//     roomHint: String,
//     require2FA: boolean,
//     type2FA: String,
//     pin: String
// }

Alexa Specific

alexa.js

Modify the **replaceCapability **function to return correct format discovery response for new capability:

// BrightnessController
if(capability == "BrightnessController")  {
	return {
			"type": "AlexaInterface",
			"interface": "Alexa.BrightnessController",
			"version": "3",
			"properties": {
				"supported": [{
					"name": "brightness"
				}],
				"proactivelyReported": reportState,
				"retrievable": reportState
			}
		};
}

func-alexa.js

Add state handler to queryDeviceState function, for example:

case "BrightnessController":
	// Return brightness percentage
	if (deviceJSON.state.hasOwnProperty('brightness') && deviceJSON.state.hasOwnProperty('time')) {
		properties.push({
				"namespace": "Alexa.BrightnessController",
				"name": "brightness",
				"value": deviceJSON.state.brightness,
				"timeOfSample": deviceJSON.state.time,
				"uncertaintyInMilliseconds": 1000
			});
	}
	break;

Web Interface Specific

device-modal.js

Add new Interface/ Capability option, for example:

<div class="form-check">
	<input title="Brightness Control" type="checkbox" class="form-check-input" name="capabilities" id="BrightnessController" value="BrightnessController">
	<label class="form-check-label" for="BrightnessController"> 
		<a data-toggle="tooltip" data-placement="right" title="Set percentage, increase, decrease, dim">Brightness <img class="octicon octicon-question" src="octicons/question.svg"></img></a>  
	</label>
	<br />
</div>

devices.ejs

Modify existing device type or add a new one, with necessary validation to enable/ disable interface/ capability. Edit/ augment the checkCapability function, for example:

else if (type.id== "LIGHT" && type.checked &&  !$('#OTHER').prop('checked')) {
	$('#simpleOptions').show();
	$('#ReportState').prop('checked', true);
	$('#stateReporting').show(); 
	$("#PowerController").prop('checked',true);
	//$('#validRangeOptions').show();
	$('input[name=appType]').each(function(index){if ($(this).attr("id") != "LIGHT") {$('input[id^='+$(this).attr("id")+']').prop("checked", false)}});
	$('input[name=capabilities]').each(function(index){
		if ($(this).attr("id") != "PowerController" && $(this).attr("id") != "BrightnessController" && $(this).attr("id") != "ColorController" && $(this).attr("id") != "ColorTemperatureController"){
			$('input[id^='+$(this).attr("id")+']').prop("checked", false);
			$('input[id^='+$(this).attr("id")+']').attr("disabled", "disabled");
		}
		else {
			if ($(this).attr("id") == "PowerController"){$('input[id^='+$(this).attr("id")+']').prop("checked", true)}
			else {$('input[id^='+$(this).attr("id")+']').prop("checked", false)}
			$('input[id^='+$(this).attr("id")+']').removeAttr("disabled"); 
		}
	});
}

You also need to consider whether further validation is required on this capability (i.e. are new modal elements used), workout the show/ hide logic and apply to:

  • clearDevice function
  • edit function

Modify generateState function to create dummy state on new device:

case "BrightnessController":
	dummyState.brightness = 75;
	break;

Modify generateState function to create dummy state on edit existing device:

case "BrightnessController":
		if (deviceState.hasOwnProperty('brightness')) {
			if (typeof deviceState.brightness == 'number' && (deviceState.brightness >= 0 || deviceState.brightness <= 100)) {
				dummyState.brightness = deviceState.brightness;
			}
		}
		else {dummyState.brightness = 75}
		break;

State API

state.js

Add handler new state objects, plus review whether there is any validation you need to do for a delta payload (range controller, thermostat and percentage use a delta payload for any "Adjust" command. For example:

if (payload.state.hasOwnProperty('brightness')) {dev.state.brightness = payload.state.brightness};

AWS Lambda Function Changes

Extend command directive to include new namespace, look for:

// Device-specific directives

Misc

Create 60x40 icon, with the same name as capability checkbox id/ value.

Node-Red-Contrib Changes

Modify Command Node "command" function, specifically switch statements for directive names, look for:

// Command Node Command Function

Note that msg.payload should always contain the target state/ operation.

Update Config Node 'updateState' function to include new state payload element(s) as-per Amazon JSON specification, look for:

// Config Node Update State

Modify Set State Node function, look for:

// Set State Node On Input Function

You'll need to modify the Command Node payload assessment, look for:

// Handle AlexaHome output

Plus modify the general payload handler, look for:

// Set State Payload Handler

Below this line ignore

Web Service Changes

index.js Changes

Modify replaceCapability function to include necessary discovery response, look for:

// Replace Capability function, replaces 'placeholders' stored under device.capabilities in mongoDB with Amazon JSON

Modify setstate function to include required state/ payload attribute assignment, look for:

// Set State Function, sets device "state" element in MongoDB based upon Node-RED MQTT 'state' message

Modify getstate API endpoint, add correct State Report JSON based on short-hand capability stored in MongoDB look for:

// Get State API, gets device "state" element from MongoDB, used for device status review in Alexa App

device-modal.ejs

Modify to include new checkbox for capability:

<div class="row" align="justify">
	<div class="col-sm">
		<fieldset class="form-group" id="capabilityType">
			<legend>Capabilities</legend>

Modify to include new Alexa App Icon (if necessary):

<div class="col-sm">
<fieldset class="form-group">
	<legend>Alexa App Icon</legend>

devices.ejs

Modify checkCapability function to include necessary logic to:

  • Auto-assign correct icon (based on Capability Name)
  • Prohibit additional selections (if necessary)
function checkCapability(check) {

Modify generateState function if this capability has a retrievable state

function generateState(deviceState) {