Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extensive Refactoring #175

Merged
merged 94 commits into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from 75 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
0c95a3e
Add Sensor device type
michikrug Mar 10, 2020
5a2068e
Add support for Contact items for Locks and OpenClose devices
michikrug Jun 4, 2020
ddb25b8
Add attributes for OpenClose devices
michikrug Jun 4, 2020
b1aa4a3
Add and update tests
michikrug Jun 4, 2020
77e07bf
Remove unnecessary customData, Rename tfaAck & tfaPin
michikrug Jun 4, 2020
e694ffe
Add note about tags to docu
michikrug Jun 4, 2020
0e1dc7b
Improve efficiency of getting items, fix synonyms
michikrug Jun 5, 2020
dfd68cb
Refactor code, increase robustness
michikrug Jun 20, 2020
11e832c
Restructure devices into single files
michikrug Jun 20, 2020
69c204c
Restructure commands into single files
michikrug Jun 20, 2020
55be634
Update dependencies, increase version
michikrug Aug 1, 2020
458fa03
Minor fixes
michikrug Aug 1, 2020
bfe28fe
Add TV device
michikrug Aug 1, 2020
a75d781
Fix select channel
michikrug Aug 1, 2020
99feb95
Fix volume relative, add onoff for TV
michikrug Aug 1, 2020
78cc754
Update documentation
michikrug Aug 13, 2020
d391504
Add temperature sensor
michikrug Aug 30, 2020
1580340
Check type attribute for sensors
michikrug Aug 30, 2020
f396de0
Change device filter logic
michikrug Aug 30, 2020
86bbfb4
Fix copy paste error
michikrug Aug 30, 2020
8bc7021
Move conversions to utilities file
michikrug Aug 30, 2020
ecf8e1f
Add tests for temperature sensor
michikrug Aug 30, 2020
42cca60
Update documentation
michikrug Aug 31, 2020
661a763
Add special color light device
michikrug Sep 1, 2020
3103582
Fix typo
michikrug Sep 1, 2020
02e5861
Minor refactoring
michikrug Sep 1, 2020
6c757cf
Fix brightness command
michikrug Sep 2, 2020
59fd3c2
Invert percentage of color temperature
michikrug Sep 2, 2020
323bcac
Make requiresItem dynamic
michikrug Sep 2, 2020
2f308df
SpecialColorLight extends Default instead of ColorLight
michikrug Sep 26, 2020
e31f8ee
Move color conversion functions to utilities
michikrug Sep 26, 2020
f4aee7a
Support OnOff for TV
michikrug Sep 26, 2020
4a70128
Fix typo
michikrug Sep 26, 2020
69470c6
Adjust volumeRelative parameter
michikrug Sep 26, 2020
5715804
Fix SpecialColorLight attributes
michikrug Sep 26, 2020
f08f7bc
Add mute command
michikrug Sep 26, 2020
149a019
Add volumeCanMuteAndUnmute for TV
michikrug Sep 26, 2020
93fe4de
Rework test structure (WIP)
michikrug Sep 29, 2020
7059c99
Make traits a function
michikrug Oct 1, 2020
abef64c
Update dependencies
michikrug Oct 1, 2020
41455e5
Add new attributes to speaker
michikrug Oct 1, 2020
2b1bed9
Fix specialcolorlight check
michikrug Oct 1, 2020
024d1c7
Remove old code
michikrug Oct 1, 2020
bd0e9fe
Make check for sensor more strict
michikrug Oct 1, 2020
81a49b9
Make check for thermostat more strict
michikrug Oct 1, 2020
54d40a3
Add alternative temperature unit attribute
michikrug Oct 1, 2020
7c63583
Remove or disable old tests
michikrug Oct 1, 2020
bd0a8a1
Extend utilities tests
michikrug Oct 1, 2020
bb94a7e
Refactor TV device
michikrug Oct 1, 2020
2ea1ee2
Add or extend tests for devices
michikrug Oct 1, 2020
6e71674
Minor fixes
michikrug Oct 1, 2020
cbbc701
Add tests for commands (WIP)
michikrug Oct 1, 2020
351a565
Add JSDoc, Remove unused defaults
michikrug Oct 1, 2020
e456046
Make mute invertable
michikrug Oct 1, 2020
c9f562c
Rework OpenClose and StartStop default conversion
michikrug Oct 1, 2020
b531aab
Add pausable attribute
michikrug Oct 1, 2020
060c21c
Add volume attributes to TV
michikrug Oct 1, 2020
90bd0fa
Update device tests
michikrug Oct 1, 2020
5e6ec44
Refactor color command tests
michikrug Oct 1, 2020
ef44d09
Add a lot of command tests
michikrug Oct 1, 2020
a145eb6
Set Volume trait when tvMute is provided
michikrug Oct 3, 2020
1c3b8ec
Add tests for default command
michikrug Oct 3, 2020
41c06dc
Add new tests for OpenHAB class
michikrug Oct 3, 2020
abfe9f2
Add tests for config
michikrug Oct 3, 2020
0e37102
Replace tab with two spaces
michikrug Oct 3, 2020
8422e02
Add ApiHandler tests
michikrug Oct 3, 2020
72aafdc
Create codeql-analysis.yml
michikrug Oct 1, 2020
e21b3e4
Rework index & openhab to be more testable
michikrug Oct 4, 2020
638f17e
Add test workflow
michikrug Oct 6, 2020
8f10aeb
Upload coverage as artifact
michikrug Oct 6, 2020
f385984
Fix intent handler calls
michikrug Oct 6, 2020
e9e7049
Only run workflows for pushes on master and PRs, Comment test coverag…
michikrug Oct 6, 2020
22a7d47
Update jest dependency
michikrug Oct 6, 2020
7c365cc
Do not use matrix builds
michikrug Oct 6, 2020
a381246
Use Node 12.x explicitly for tests
michikrug Oct 7, 2020
ce2d866
Fix two-factor auth
michikrug Dec 30, 2020
01716ee
Adjust test for two-factor auth
michikrug Dec 30, 2020
98c56b2
Add useKelvin option for SpecialColorLight
michikrug Jan 1, 2021
3894cd5
Update documentation
michikrug Jan 1, 2021
7806b39
Consistent naming of useFahrenheit
michikrug Jan 1, 2021
822bd0c
Refactor commands
michikrug Jan 1, 2021
6c22c93
Update dependencies, add linting
michikrug Jan 1, 2021
c93725b
Adjust thermostat modes to use array
michikrug Nov 6, 2020
a0c58d5
Fix test workflow
michikrug Jan 1, 2021
e1340eb
Udate codeql workflow
michikrug Jan 1, 2021
4f1ca5a
Update workflows
michikrug Jan 1, 2021
4fa6861
Update documentation
michikrug Feb 4, 2021
6ffa1c7
Change test-ci script command
michikrug Feb 4, 2021
ea69f4e
Make colorTemperatureRange optional if useKelvin is set
michikrug Feb 4, 2021
fa6c605
Switch workflows to main branch
michikrug Feb 5, 2021
b31d037
Add prettier for code formatting
michikrug Feb 9, 2021
cd6b822
Apply code formatting
michikrug Feb 9, 2021
ae6055d
Add compatibility for previous tfa attributes
michikrug Feb 9, 2021
d78b302
Update dependencies
michikrug Feb 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "standard"
}
23 changes: 0 additions & 23 deletions .eslintrc.json

This file was deleted.

65 changes: 65 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: CodeQL

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ["javascript"]
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Tests

on:
push:
branches:
- master
pull_request:
branches:
- master
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not run the tests when pushing to a new branch without an open pull request?
And why only run the tests on pull requests into master?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we?

If you push to a PR'd branch it is run every time and can be used to properly review and approve changes.

All branch pushes and PRs not going into master are not of interest and can be run during development locally. (Think green, safe resources :D)

What would be your reasoning to do it every time?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah saving resources makes sense. I just thought about a more flexible setup which ensures the tests are always executed regardless of the branch and pull request. GitHub makes it too cheap running too many tests.


jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- run: npm ci
- run: npm run build --if-present
- run: npm test
- name: Upload Test Coverage
uses: actions/upload-artifact@v2
with:
name: coverage
path: coverage/
- name: Comment Test Coverage
if: ${{ github.event_name == 'pull_request' }}
uses: romeovs/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ Currently the following metadata values are supported (also depending on Googles
* `Switch { ga="Sprinkler" }`
* `Switch { ga="Vacuum" }`
* `Switch { ga="Scene" }`
* `Switch { ga="Lock" [ tfaAck=true ] }`
* `Switch { ga="SecuritySystem" [ tfaPin="1234" ] }`
* `Switch / Contact { ga="Lock" [ ackNeeded=true ] }`
* `Switch { ga="SecuritySystem" [ pinNeeded="1234" ] }`
* `Dimmer { ga="Speaker" }`
* `Switch / Dimmer { ga="Fan" [ speeds="0=away:zero,50=default:standard:one,100=high:two", lang="en", ordered=true ] }` (for Dimmer the options have to be set)
* `Switch / Dimmer { ga="Hood" }`
Expand All @@ -223,14 +223,15 @@ Currently the following metadata values are supported (also depending on Googles
* `Rollershutter { ga="Pergola" }`
* `Rollershutter { ga="Shutter" }`
* `Rollershutter { ga="Window" }`
* `Group { ga="Thermostat" [ modes="..." ] }`
* `Group { ga="Thermostat" [ modes="...", useFahrenheit=true ] }`
* `Number { ga="thermostatTemperatureAmbient" }` as part of Thermostat group
* `Number { ga="thermostatHumidityAmbient" }` as part of Thermostat group
* `Number { ga="thermostatTemperatureSetpoint" }` as part of Thermostat group
* `Number / String { ga="thermostatMode" }` as part of Thermostat group
* `Number { ga="TemperatureSensor" } [ useFahrenheit=true ] `
* `String { ga="Camera" [ protocols="hls,dash" ] }`

_\* All Rollershutter devices can also be used with a Switch item with the limitation of only supporting open and close states._
_\* All Rollershutter devices can also be used with a Switch or Contact item with the limitation of only supporting open and close states._

Item labels are not mandatory in openHAB, but for the Google Assistant Action they are absolutely necessary!

Expand All @@ -242,6 +243,11 @@ Furthermore, you can state synonyms for the device name: `Switch KitchenLight "K

To ease setting up new devices you can add a room hint: `[ roomHint="Living Room" ]`.

For devices supporting the OpenClose trait, the attributes `[ discreteOnlyOpenClose=false, queryOnlyOpenClose=false ]` can be configured.
- discreteOnlyOpenClose defaults to false. When set to true, this indicates that the device must either be fully open or fully closed (that is, it does not support values between 0% and 100%). An example of such a device may be a valve.
- queryOnlyOpenClose defaults to false. Is set to true for `Contact` items. Indicates if the device can only be queried for state information and cannot be controlled. Sensors that can only report open state should set this field to true.

---

NOTE: metadata is not (yet?) available via paperUI. Either you create your items via ".items" files, or you can:
- add metadata via console:
Expand All @@ -258,6 +264,9 @@ NOTE: metadata is not (yet?) available via paperUI. Either you create your items
}
```

NOTE: Please be aware that for backward compatibilty also the former usage of tags (ref. [Google Assistant Action Documentation v2.5](https://www.openhab.org/v2.5/docs/ecosystem/google-assistant/)) to specify items to be exposed to Google Assistent is supported and may cause unexpected behavior.
Items that contain tags that refer to a valid Google Assistent device will be exposed regardless of having metadata set. E.g.: `Switch MyBulb ["Lighting"]`.

### Special item configurations

#### Two-Factor-Authentication
Expand All @@ -273,8 +282,8 @@ _pinNeeded_: "A two-factor authentication that requires a personal identificatio
Example:

```
Switch DoorLock "Front Door" { ga="Lock" [ tfaAck=true ] }
Switch HouseAlarm "House Alarm" { ga="SecuritySystem" [ tfaPin="1234" ] }
Switch DoorLock "Front Door" { ga="Lock" [ ackNeeded=true ] }
Switch HouseAlarm "House Alarm" { ga="SecuritySystem" [ pinNeeded="1234" ] }
```

#### Thermostats
Expand All @@ -300,6 +309,7 @@ E.g. `[ modes="off=OFF:WINDOW_OPEN,heat=COMFORT:BOOST,eco=ECO,on=ON,auto" ]` wil
By default the integration will provide `"off,heat,cool,on,heatcool,auto,eco"`.

You can also set up a Thermostat for using it as a temperature sensor. To do so, create a Thermostat group and only add one item member as "thermostatTemperatureAmbient".
However, it is recommended to prefer the `TemperatureSensor` type for simple temperature reports (but currently no UI support in Google Assistant).

#### Fans

Expand All @@ -319,6 +329,11 @@ Blinds should always use the `Rollershutter` item type.
Since Google and openHAB use the oposite percentage value for "opened" or "closed", the action will tranlate this automatically.
If the values are still inverted in your case, you can state the `[ inverted=true ]` option for all `Rollershutter` items.

Since Google only tells the open percentage (and not the verb "close" or "down"), it can not be differentiated between saying "set blind to 100%" or "open blind".
Therefore, it is not possible to "not invert" the verbs, if the user chooses to invert the numbers.

---

More details about the setup and the service linkage (https://myopenhab.org) procedure within the Google App can be found in the [USAGE documentation](docs/USAGE.md).

## Example Voice Commands
Expand Down
25 changes: 19 additions & 6 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Currently the following metadata values are supported (also depending on Googles
* `Switch { ga="Sprinkler" }`
* `Switch { ga="Vacuum" }`
* `Switch { ga="Scene" }`
* `Switch { ga="Lock" [ tfaAck=true ] }`
* `Switch { ga="SecuritySystem" [ tfaPin="1234" ] }`
* `Switch / Contact { ga="Lock" [ ackNeeded=true ] }`
* `Switch { ga="SecuritySystem" [ pinNeeded="1234" ] }`
* `Dimmer { ga="Speaker" }`
* `Switch / Dimmer { ga="Fan" [ speeds="0=away:zero,50=default:standard:one,100=high:two", lang="en", ordered=true ] }` (for Dimmer the options have to be set)
* `Switch / Dimmer { ga="Hood" }`
Expand All @@ -51,14 +51,15 @@ Currently the following metadata values are supported (also depending on Googles
* `Rollershutter { ga="Pergola" }`
* `Rollershutter { ga="Shutter" }`
* `Rollershutter { ga="Window" }`
* `Group { ga="Thermostat" [ modes="..." ] }`
* `Group { ga="Thermostat" [ modes="...", useFahrenheit=true ] }`
* `Number { ga="thermostatTemperatureAmbient" }` as part of Thermostat group
* `Number { ga="thermostatHumidityAmbient" }` as part of Thermostat group
* `Number { ga="thermostatTemperatureSetpoint" }` as part of Thermostat group
* `Number / String { ga="thermostatMode" }` as part of Thermostat group
* `Number { ga="TemperatureSensor" } [ useFahrenheit=true ] `
* `String { ga="Camera" [ protocols="hls,dash" ] }`

_\* All Rollershutter devices can also be used with a Switch item with the limitation of only supporting open and close states._
_\* All Rollershutter devices can also be used with a Switch or Contact item with the limitation of only supporting open and close states._

Example item configuration:
```
Expand Down Expand Up @@ -87,6 +88,11 @@ Furthermore, you can state synonyms for the device name: `Switch KitchenLight "K

To ease setting up new devices you can add a room hint: `[ roomHint="Living Room" ]`.

For devices supporting the OpenClose trait, the attributes `[ discreteOnlyOpenClose=false, queryOnlyOpenClose=false ]` can be configured.
- discreteOnlyOpenClose defaults to false. When set to true, this indicates that the device must either be fully open or fully closed (that is, it does not support values between 0% and 100%). An example of such a device may be a valve.
- queryOnlyOpenClose defaults to false. Is set to true for `Contact` items. Indicates if the device can only be queried for state information and cannot be controlled. Sensors that can only report open state should set this field to true.

---

NOTE: metadata is not (yet?) available via paperUI. Either you create your items via ".items" files, or you can:
- add metadata via console:
Expand All @@ -103,6 +109,9 @@ NOTE: metadata is not (yet?) available via paperUI. Either you create your items
}
```

NOTE: Please be aware that for backward compatibilty also the former usage of tags (ref. [Google Assistant Action Documentation v2.5](https://www.openhab.org/v2.5/docs/ecosystem/google-assistant/)) to specify items to be exposed to Google Assistent is supported and may cause unexpected behavior.
Items that contain tags that refer to a valid Google Assistent device will be exposed regardless of having metadata set. E.g.: `Switch MyBulb ["Lighting"]`.

### Special item configurations

#### Two-Factor-Authentication
Expand All @@ -118,8 +127,8 @@ _pinNeeded_: "A two-factor authentication that requires a personal identificatio
Example:

```
Switch DoorLock "Front Door" { ga="Lock" [ tfaAck=true ] }
Switch HouseAlarm "House Alarm" { ga="SecuritySystem" [ tfaPin="1234" ] }
Switch DoorLock "Front Door" { ga="Lock" [ ackNeeded=true ] }
Switch HouseAlarm "House Alarm" { ga="SecuritySystem" [ pinNeeded="1234" ] }
```

#### Thermostats
Expand All @@ -145,6 +154,7 @@ E.g. `[ modes="off=OFF:WINDOW_OPEN,heat=COMFORT:BOOST,eco=ECO,on=ON,auto" ]` wil
By default the integration will provide `"off,heat,cool,on,heatcool,auto,eco"`.

You can also set up a Thermostat for using it as a temperature sensor. To do so, create a Thermostat group and only add one item member as "thermostatTemperatureAmbient".
However, it is recommended to prefer the `TemperatureSensor` type for simple temperature reports (but currently no UI support in Google Assistant).

#### Fans

Expand All @@ -164,6 +174,9 @@ Blinds should always use the `Rollershutter` item type.
Since Google and openHAB use the oposite percentage value for "opened" or "closed", the action will tranlate this automatically.
If the values are still inverted in your case, you can state the `[ inverted=true ]` option for all `Rollershutter` items.

Since Google only tells the open percentage (and not the verb "close" or "down"), it can not be differentiated between saying "set blind to 100%" or "open blind".
Therefore, it is not possible to "not invert" the verbs, if the user chooses to invert the numbers.


## Setup & Usage on Google Assistant App

Expand Down
36 changes: 30 additions & 6 deletions functions/apihandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,33 @@
const https = require('https');

class ApiHandler {
constructor(config = {}, authToken = '') {
/**
* @param {object} config
*/
constructor(config = { host: '', path: '/rest/items/', port: 80 }) {
if (!config.path.startsWith('/')) {
config.path = '/' + config.path;
}
if (!config.path.endsWith('/')) {
config.path += '/';
}
this._config = config;
this._authToken = '';
}

/**
* @param {string} authToken
*/
set authToken(authToken) {
this._authToken = authToken;
}

getOptions(method = 'GET', itemName = '', length = 0) {
/**
* @param {string} method
* @param {string} itemName
* @param {number} length
*/
getOptions(method = 'GET', itemName = '', length = 0) {
const queryString = '?metadata=ga,synonyms' + (itemName ? '' : '&fields=groupNames,groupType,name,label,metadata,tags,type');
const options = {
hostname: this._config.host,
Expand All @@ -43,7 +61,7 @@ class ApiHandler {

if (this._config.userpass) {
options.auth = this._config.userpass;
} else {
} else if (this._authToken) {
options.headers['Authorization'] = 'Bearer ' + this._authToken;
}

Expand All @@ -55,7 +73,9 @@ class ApiHandler {
return options;
}


/**
* @param {string} itemName
*/
getItem(itemName = '') {
const options = this.getOptions('GET', itemName);
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -86,7 +106,11 @@ class ApiHandler {
return this.getItem();
}

sendCommand(itemName = '', payload = '') {
/**
* @param {string} itemName
* @param {string} payload
*/
sendCommand(itemName, payload) {
const options = this.getOptions('POST', itemName, payload.length);
return new Promise((resolve, reject) => {
const req = https.request(options, (response) => {
Expand All @@ -104,4 +128,4 @@ class ApiHandler {
}
}

module.exports = { ApiHandler };
module.exports = ApiHandler;
Loading