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

feat(notification): add philips hue #681

Merged
merged 24 commits into from
Nov 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
adc088c
feat: Add Philips Hue notification support
MattieX Nov 3, 2020
a999d9a
docs: add Philips Hue notification to README
MattieX Nov 3, 2020
79c72c8
docs: Move Philips Hue to be alphabetical in list, add "Optional" to …
banksio Nov 3, 2020
4e54c24
feat(hue): Add cloud connection support
MattieX Nov 3, 2020
d248ea2
refactor(hue): Cloud connection uses existing API key
banksio Nov 4, 2020
88d0dc5
refactor(hue): rename environment variables
MattieX Nov 4, 2020
7b3409b
Merge branch 'philips-hue-notifications' of https://github.com/Mattie…
MattieX Nov 4, 2020
20571dd
refactor(hue): Require Hue API key for both LAN and Cloud access
banksio Nov 4, 2020
3c696ab
docs(hue): Add docs for Philips Hue cloud integration
banksio Nov 4, 2020
a85c6ff
feat(hue): Add light blinking support
banksio Nov 4, 2020
92b1007
refactor: Rename instances of hue to philips_hue
banksio Nov 4, 2020
8c4db16
refactor(philips_hue): remove redundant function and clean imports an…
MattieX Nov 4, 2020
af3798c
Merge branch 'philips-hue-notifications' of https://github.com/Mattie…
MattieX Nov 4, 2020
5117f24
Merge branch 'main' into philips-hue-notifications
banksio Nov 4, 2020
5cdb5e9
refactor(philips-hue): Syntax fixes
banksio Nov 4, 2020
75aebd7
refactor(philips-hue): Proper error handling for Promises (no-floatin…
banksio Nov 4, 2020
d29a7b1
Merge branch 'main' into philips-hue-notifications
banksio Nov 4, 2020
a7440b9
refactor(philips-hue): Change environment variables from HUE_ to PHIL…
banksio Nov 4, 2020
a3e9d16
Merge branch 'philips-hue-notifications' of https://github.com/Mattie…
banksio Nov 4, 2020
57cf47b
docs(philips-hue): Update README to match new environment variable na…
banksio Nov 4, 2020
0322279
Merge branch 'main' into philips-hue-notifications
jef Nov 5, 2020
9b240fd
refactor(philips-hue): Move type import to top of file
banksio Nov 5, 2020
84614e0
Merge branch 'main' into philips-hue-notifications
jef Nov 5, 2020
27346b9
docs: Remove redundant tag from README
MattieX Nov 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ PAGE_SLEEP_MAX=
PAGE_TIMEOUT=
PAGERDUTY_INTEGRATION_KEY=
PAGERDUTY_SEVERITY=
PHILIPS_HUE_API_KEY=
PHILIPS_HUE_CLOUD_ACCESS_TOKEN=
PHILIPS_HUE_CLOUD_CLIENT_ID=
PHILIPS_HUE_CLOUD_CLIENT_SECRET=
PHILIPS_HUE_CLOUD_REFRESH_TOKEN=
PHILIPS_HUE_LAN_BRIDGE_IP=
PHILIPS_HUE_LIGHT_COLOR=
PHILIPS_HUE_LIGHT_IDS=
PHILIPS_HUE_LIGHT_PATTERN=
PHONE_CARRIER=
PHONE_NUMBER=
PLAY_SOUND=
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,23 @@ environment variables are **optional**._
| `PAGERDUTY_SEVERITY` | Severity of PagerDuty events | Default: `info` |

</details>
<details>
<summary>Philips Hue</summary>

| Environment variable | Description | Notes |
|:---:|---|---|
| `PHILIPS_HUE_API_KEY` | Hue Bridge API Key | **Required**, generate key using instructions [here](https://developers.meethue.com/develop/get-started-2/). This will be used for both LAN and cloud access over the official Remote Hue API. |
| `PHILIPS_HUE_LAN_BRIDGE_IP` | LAN IP Address of your Hue Bridge | LAN only, e.g. `192.168.x.x`|
| `PHILIPS_HUE_LIGHT_IDS` | Light IDs | Optional (all if not supplied). Comma seperated, e.g.: `1`, `2` |See Hue App → About for IDs |
| `PHILIPS_HUE_LIGHT_COLOR` | Color in RGB Format | Optional (NVIDIA green if not supplied). Comma separated, e.g.: `255`, `255`, `255`|
| `PHILIPS_HUE_LIGHT_PATTERN` | `blink` or empty | Optional - lights will flash for 30 seconds if `blink` is supplied. |
| `PHILIPS_HUE_CLOUD_ACCESS_TOKEN` | Remote Access Token | Cloud only, the access token obtained from Philips's Remote Hue API. Instructions to generate [here](https://developers.meethue.com/develop/hue-api/remote-authentication/). |
| `PHILIPS_HUE_CLOUD_REFRESH_TOKEN` | Remote Refresh Token | Cloud only, the refresh token obtained from Philips's Remote Hue API. |
| `PHILIPS_HUE_CLOUD_CLIENT_ID` | Remote Client ID | Cloud only, the client ID to use when accessing the Remote Hue API. |
| `PHILIPS_HUE_CLOUD_CLIENT_SECRET` | Remote Client Secret | Cloud only, the client secret to use when accessing the Remote Hue API. |


</details>
<details>
<summary>Pushbullet</summary>

Expand Down Expand Up @@ -414,8 +430,15 @@ environment variables are **optional**._

</details>




</details>





## FAQ

**Q: What's Node.js and how do I install it?** Visit [their website](https://nodejs.org/en/) and download and install
Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"messaging-api-telegram": "^1.0.1",
"mqtt": "^4.2.4",
"node-fetch": "^2.6.1",
"node-hue-api": "^4.0.9",
"node-notifier": "^8.0.0",
"node-pagerduty": "^1.3.5",
"nodemailer": "^6.4.14",
Expand Down
12 changes: 12 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@ const notifications = {
integrationKey: envOrString(process.env.PAGERDUTY_INTEGRATION_KEY),
severity: envOrString(process.env.PAGERDUTY_SEVERITY, 'info')
},
philips_hue: {
accessToken: envOrString(process.env.PHILIPS_HUE_CLOUD_ACCESS_TOKEN),
apiKey: envOrString(process.env.PHILIPS_HUE_API_KEY),
bridgeIp: envOrString(process.env.PHILIPS_HUE_LAN_BRIDGE_IP),
clientId: envOrString(process.env.PHILIPS_HUE_CLOUD_CLIENT_ID),
clientSecret: envOrString(process.env.PHILIPS_HUE_CLOUD_CLIENT_SECRET),
lightColor: envOrString(process.env.PHILIPS_HUE_LIGHT_COLOR),
lightIds: envOrString(process.env.PHILIPS_HUE_LIGHT_IDS),
lightPattern: envOrString(process.env.PHILIPS_HUE_LIGHT_PATTERN),
refreshToken: envOrString(process.env.PHILIPS_HUE_CLOUD_REFRESH_TOKEN),
remoteApiUsername: envOrString(process.env.PHILIPS_HUE_API_KEY)
},
phone: {
availableCarriers: new Map([
['att', 'txt.att.net'],
Expand Down
2 changes: 2 additions & 0 deletions src/notification/notification.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Link, Store} from '../store/model';
import {adjustPhilipsHueLights} from './philips-hue';
import {playSound} from './sound';
import {sendDesktopNotification} from './desktop';
import {sendDiscordMessage} from './discord';
Expand All @@ -21,6 +22,7 @@ export function sendNotification(link: Link, store: Store) {
sendSms(link, store);
sendDesktopNotification(link, store);
// Non-priority
adjustPhilipsHueLights();
sendDiscordMessage(link, store);
sendMqttMessage(link, store);
sendPagerDutyNotification(link, store);
Expand Down
108 changes: 108 additions & 0 deletions src/notification/philips-hue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import type Api from 'node-hue-api/lib/api/Api';
import {config} from '../config';
import {v3 as hueAPI} from 'node-hue-api';
import {logger} from '../logger';

const hue = config.notifications.philips_hue;
const apiKey = hue.apiKey;
const bridgeIp = hue.bridgeIp;
const lightIds = hue.lightIds;
const lightColor = hue.lightColor;
const lightPattern = hue.lightPattern;
const LightState = hueAPI.lightStates.LightState;
const clientId = hue.clientId;
const clientSecret = hue.clientSecret;
const accessToken = hue.accessToken;
const refreshToken = hue.refreshToken;
const remoteApiUsername = hue.remoteApiUsername;

// Default Light State
const lightState = new LightState()
.on(true)
.brightness(100)
.rgb(46.27, 72.55, 0);

const adjustLightsWithAPI = (hueBridge: Api) => {
logger.debug('Connected to Philips Hue bridge.');
// Set the custom light state (COLOR and METHOD here)
if (lightColor) {
const rgbArray = lightColor.split(',');
// If there's not three values, must not be RGB
if (rgbArray.length === 3) {
lightState.rgb(rgbArray[0], rgbArray[1], rgbArray[2]);
} else {
logger.debug('✖ Error assigning RGB Values');
}
}

// If blink is specified, then blink the lights
if (lightPattern === 'blink') {
lightState.alertLong();
}

// If we've been given light IDs, then only adjust those IDs
if (lightIds) {
const arrayOfIDs = lightIds.split(',');
arrayOfIDs.forEach(light => {
logger.debug('adjusting all hue lights');
(hueBridge.lights.setLightState(light, lightState) as Promise<any>).catch((error: Error) => {
logger.error('Failed to adjust all lights.');
logger.error(error);
throw error;
});
});
} else { // Adjust all light IDs
hueBridge.lights.getAll().then((allLights: any[]) => {
allLights.forEach((light: any) => {
logger.debug('adjusting specified lights');
(hueBridge.lights.setLightState(light, lightState) as Promise<any>).catch((error: Error) => {
logger.error('Failed to adjust specified lights.');
logger.error(error);
throw error;
});
});
}).catch((error: Error) => {
logger.error('Failed to get all lights.');
logger.error(error);
throw error;
});
}
};

export function adjustPhilipsHueLights() {
// Check if the required variables have been set
if (hue.apiKey && hue.bridgeIp) {
logger.info('↗ adjusting Philips Hue lights over LAN');
(async () => {
logger.debug('Attempting to connect to Philips Hue bridge at ' + bridgeIp);
hueAPI.api.createLocal(bridgeIp).connect(apiKey).then(
hueBridge => {
adjustLightsWithAPI(hueBridge);
logger.info('✔ adjusted Philips Hue lights over LAN');
},
(error: Error) => {
logger.error('✖ couldn\'t adjust hue lights.', error);
});
})();
} else if (hue.apiKey && hue.clientId && hue.clientSecret) {
logger.info('↗ adjusting Philips Hue lights over cloud');
(async () => {
logger.debug('Attempting to connect to Philips Hue bridge over cloud');
const remoteBootstrap = hueAPI.api.createRemote(clientId, clientSecret);
if (hue.accessToken && hue.refreshToken) {
remoteBootstrap.connectWithTokens(accessToken, refreshToken, remoteApiUsername)
.then(hueBridge => {
adjustLightsWithAPI(hueBridge);
logger.info('✔ adjusted Philips Hue lights over cloud');
},
(error: Error) => {
logger.error('Failed to get a remote Philips Hue connection using supplied tokens.');
logger.error(error);
throw error;
});
}
})();
} else {
logger.error('✖ couldn\'t adjust hue lights');
}
}