Skip to content

Commit

Permalink
Merge branch 'release/v0.0.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
Claudio Chimera authored and Claudio Chimera committed May 23, 2021
2 parents a2ea09d + 164f677 commit b651e69
Show file tree
Hide file tree
Showing 8 changed files with 1,328 additions and 1,094 deletions.
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
26 changes: 26 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: NPM Publish

on:
release:
types: [created]

jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

update-nodered:
runs-on: ubuntu-latest
needs: [publish-npm]
steps:
- uses: Hacksore/node-red-flow@v2
with:
repo: node-red-contrib-alexa-virtual-smarthome
118 changes: 114 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [Setup Instructions](#setup-instructions)
- [The Config node](#the-config-node)
- [The Device node](#the-device-node)
- [Troubleshooting](#troubleshooting)
- [Credits](#credits)
- [Copyright and license](#copyright-and-license)

Expand All @@ -21,10 +22,11 @@ This module does NOT directly interface with devices made by Amazon.
## Prerequisites

1. A 'real' SSL certificate e.g. from [Let’s Encrypt](https://letsencrypt.org).
2. Forward TCP traffic coming in from the Internet to your Node-RED server.
3. An updated NodeJS version.
4. An Amazon developer account (use the same username used in the Amazon Alexa App or devices).
5. An Amazon Web Service (AWS) account (use the same username used in the Amazon Alexa App or devices).
2. A reverse proxy, like nginx, forwarding the right request to the Node-RED server.
3. Forward TCP traffic coming in from the Internet to your reverse proxy server.
4. An updated NodeJS version.
5. An Amazon developer account (use the same username used in the Amazon Alexa App or devices).
6. An Amazon Web Service (AWS) account (use the same username used in the Amazon Alexa App or devices).

---
## Setup Instructions
Expand Down Expand Up @@ -268,6 +270,114 @@ This is the "real" device node, configure the following info:
* "Display categories": the display categories. See [Display categories](https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-discovery.html#display-categories) for more info.
* "Interfaces": the interfaces supported by the device. See [Interfaces](https://developer.amazon.com/en-US/docs/alexa/device-apis/list-of-interfaces.html) for more info.

## Troubleshooting

This is a checklist for the config:

### Check the forward rule for /alexa/oauth

* Open your browser at "https://YOUR_DOMAIN.COM/alexa/oauth"
* You should get the message "Wrong client id". If not, check your port forwarding the reverse proxy config or reverse proxy config.


### Check the forward rule for /alexa/token
* Enable the debug log in the Node-Red Alexa node configuration.
* Open your browser at "https://YOUR_DOMAIN.COM/alexa/token"
* You should get the message "https://YOUR_DOMAIN.COM/alexa/token". If not, check your port forwarding the reverse proxy config or reverse proxy config.

### Check the forward rule for /alexa/smarhome
* Enable the debug log in the Node-Red Alexa node configuration.
* Open your browser at "https://YOUR_DOMAIN.COM/alexa/smarhome"
* You should get the message "https://YOUR_DOMAIN.COM/alexa/smarhome". If not, check your port forwarding the reverse proxy config or reverse proxy config.

### Check the lambda function

* Enable the debug log in the Node-Red Alexa node configuration.
* Open your browser at [AWS lambda](https://eu-west-1.console.aws.amazon.com/lambda/home)
* Click on the "SmartHome" function
* Click on the "Execute Test" tab
* Paste the following message on the editor:

```
{
"directive": {
"header": {
"namespace": "Test",
"name": "Test",
"messageId": "<message id>",
"payloadVersion": "3"
},
"payload": {
"grant": {
"type": "OAuth2.AuthorizationCode",
"code": "Test"
},
"grantee": {
"type": "BearerToken",
"token": "Test"
}
}
}
}
```
* Click on "Execute test" button
* Click on detail, You should see the following response:
```
{
"ok": "ok"
}
```

### Check the Alexa account linking

* Enable the debug log in the Node-Red Alexa node configuration.
* Follow the - [Link your account with your Smart Home skill](#Link-your-account-with-your-Smart-Home-skill)
* Open the Node-RED gui, and check the debug window, You should see the following info:

```
node: Alexa
msg : string[15]
"oauth_get login"
```

```
node: Alexa
msg : string[17]
"oauth_get profile"
```

```
node: Alexa
msg : string[37]
"Username [email protected] authorized"
```

```
node: Alexa
msg : string[29]
"token_post authorization_code"
```

```
node: Alexa
msg : string[37]
"smarthome_post: oauth_get AcceptGrant"
```

### Nginx reverse proxy configuration

Following is a sample forwarding config for Nginx

```
location ~ ^/alexa/(oauth|token|smarthome) {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://192.168.0.3:3001;
}
```


## Credits
Parts of this README and large parts of the code comes from Amazon guide.
Expand Down
120 changes: 111 additions & 9 deletions alexa/alexa-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ module.exports = function (RED) {
node.app.get(path.join(node.http_root, OAUTH_PATH), urlencodedParser, function (req, res) { node.oauth_get(req, res); });
node.app.post(path.join(node.http_root, OAUTH_PATH), urlencodedParser, function (req, res) { node.oauth_post(req, res); });
node.app.post(path.join(node.http_root, TOKEN_PATH), urlencodedParser, function (req, res) { node.token_post(req, res); });
if (node.config.verbose) {
node.app.get(path.join(node.http_root, TOKEN_PATH), urlencodedParser, function (req, res) { node.token_get(req, res); });
node.app.get(path.join(node.http_root, SMART_HOME_PATH), urlencodedParser, function (req, res) { node.smarthome_get(req, res); });
}
if (node.config.msg_check) {
node.app.post(path.join(node.http_root, SMART_HOME_PATH), jsonParser, function (req, res) { node.smarthome_post_verify(req, res); });
} else {
Expand Down Expand Up @@ -378,6 +382,17 @@ module.exports = function (RED) {
return res.redirect(util.format('%s?state=%s&code=%s', redirect_uri, state, node.auth_code.code));
}

//
//
//
//
token_get(req, res) {
var node = this;
if (node.config.verbose) node._debug('token_get');
const uri = 'https://' + path.join(req.get('Host'), node.http_root, TOKEN_PATH);
res.status(200).send(uri);
}

//
//
//
Expand Down Expand Up @@ -463,6 +478,17 @@ module.exports = function (RED) {
return res.status(401).send('Unauthorized');
}

//
//
//
//
smarthome_get(req, res) {
var node = this;
if (node.config.verbose) node._debug('smarthome_get');
const uri = 'https://' + path.join(req.get('Host'), node.http_root, SMART_HOME_PATH);
res.status(200).send(uri);
}

//
//
//
Expand Down Expand Up @@ -854,7 +880,10 @@ module.exports = function (RED) {
.then(pres => {
if (node.config.verbose) node._debug("get_user_profile CCHI res " + JSON.stringify(pres));
if (node.config.emails.includes(pres.email)) {
if (node.config.verbose) node._debug(pres.email + ' OK');
if (node.config.verbose) {
node._debug(pres.email + ' OK');
node.error("Username " + pres.email + " authorized");
}
node.auth_code = {
code: node.tokgen.generate(),
expire_at: Date.now() + 60 * 2 * 1000
Expand All @@ -863,6 +892,7 @@ module.exports = function (RED) {
node.redirect_to_amazon(ores, node.auth_code.code);
} else {
if (node.config.verbose) node._debug(pres.email + ' NOK');
node.error("Username " + pres.email + " not authorized");
node.redirect_to_login_page(ores, true);
}
})
Expand Down Expand Up @@ -909,6 +939,36 @@ module.exports = function (RED) {
return res.redirect(url);
}

//
//
//
//
get_all_states() {
var node = this;
let states = {};
Object.keys(node.devices).forEach(function (key) {
const device = node.devices[key];
if (Object.keys(device.state).length > 0) {
states[device.id] = device.state;
}
});
return states;
}

//
//
//
//
get_all_names() {
var node = this;
let names = {};
Object.keys(node.devices).forEach(function (key) {
const device = node.devices[key];
names[device.id] = device.config.name;
});
return names;
}

//
//
//
Expand Down Expand Up @@ -944,13 +1004,54 @@ module.exports = function (RED) {
//
//
//
report_state(endpointId) {
// https://developer.amazon.com/en-US/docs/alexa/smarthome/state-reporting-for-a-smart-home-skill.html
// https://developer.amazon.com/en-US/docs/alexa/smarthome/send-events-to-the-alexa-event-gateway.html
send_doorbell_press(endpointId, cause) {
// https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-doorbelleventsource.html
var node = this;
if (node.config.verbose) node._debug('report_state ' + endpointId);
const state = node.get_change_report(endpointId);
if (node.config.verbose) node._debug('report_state ' + JSON.stringify(state));
if (node.config.verbose) node._debug('send_doorbell_press' + cause);

node.get_access_token('evn')
.then(access_token => {
const state = {
context: {},
event: {
header: {
namespace: "Alexa.DoorbellEventSource",
name: "DoorbellPress",
messageId: node.tokgen.generate(),
payloadVersion: "3"
},
endpoint: {
scope: {
type: "BearerToken",
token: access_token
},
endpointId: endpointId
},
payload: {
cause: {
type: cause || "PHYSICAL_INTERACTION"
},
timestamp: new Date().toISOString()
}
},
};
if (node.config.verbose) node._debug('send_doorbell_press ' + JSON.stringify(state));
superagent
.post(node.config.event_endpoint)
.set('Authorization', 'Bearer ' + access_token)
.send(state)
.end((err, res) => {
if (err) {
node.error('send_doorbell_press err ' + JSON.stringify(err));
} else {
if (node.config.verbose) node._debug('send_doorbell_press res ' + JSON.stringify(res));
}
});
if (node.config.verbose) node._debug('send_doorbell_press sent');
})
.catch(err => {
node.error('send_doorbell_press get_access_token err ' + JSON.stringify(err));
})
}

//
Expand Down Expand Up @@ -985,11 +1086,11 @@ module.exports = function (RED) {
if (node.config.verbose) node._debug('send_change_report res ' + JSON.stringify(res));
}
});
if (node.config.verbose) node._debug('send_change_report sent');
})
.catch(err => {
node.error('send_change_report get_access_token err ' + JSON.stringify(err));
})
if (node.config.verbose) node._debug('send_change_report sent');
}

//
Expand Down Expand Up @@ -1107,6 +1208,7 @@ module.exports = function (RED) {
}
const oauth2_bearer_token = node.tokens.evn.access_token;
const properties = node.devices[endpointId].getProperties();
if (node.config.verbose) node._debug('endpointId ' + endpointId +' properties ' + JSON.stringify(properties));
if (changed_propertie_names && changed_propertie_names.length > 0) {
properties.forEach(property => {
if (changed_propertie_names && changed_propertie_names.includes(property.name)) {
Expand Down Expand Up @@ -1186,7 +1288,7 @@ module.exports = function (RED) {
if (node.config.verbose) node._debug("CCHI state " + JSON.stringify(state));
}
} else {
// TODO all states
// TODO all states??
}
}

Expand Down
2 changes: 1 addition & 1 deletion alexa/alexa-device.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
</div>
</div>

<div class="form-row red-ui-editableList-border div_trait" hidden id="i_doorbell_event_source" style="background: #fbfbfb; padding: 5px;">
<div class="form-row red-ui-editableList-border div_trait" id="i_doorbell_event_source" style="background: #fbfbfb; padding: 5px;">
<div class="form-row">
<input type="checkbox" id="node-input-i_doorbell_event_source" style="display:inline-block; width:20px; vertical-align:baseline;">
<span data-i18n="alexa-device.interface.doorbell_event_source">
Expand Down
Loading

0 comments on commit b651e69

Please sign in to comment.