node-red-contrib-homebridge-automation 0.1.11 → 0.1.12-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: npm
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "10:00"
8
+ open-pull-requests-limit: 10
9
+ ignore:
10
+ - dependency-name: documentation
11
+ versions:
12
+ - 13.2.0
13
+ - 13.2.1
@@ -0,0 +1,93 @@
1
+ #!/bin/env node
2
+
3
+ /**
4
+ * This scripts queries the npm registry to pull out the latest version for a given tag.
5
+ */
6
+
7
+ const fs = require("fs");
8
+ const semver = require("semver");
9
+ const child_process = require("child_process");
10
+ const assert = require("assert");
11
+
12
+ const BRANCH_VERSION_PATTERN = /^([A-Za-z]*)-(\d+.\d+.\d+)$/
13
+
14
+ // Load the contents of the package.json file
15
+ const packageJSON = JSON.parse(fs.readFileSync("package.json", "utf8"));
16
+
17
+ let refArgument = process.argv[2];
18
+ let tagArgument = process.argv[3] || "latest";
19
+
20
+ if (refArgument == null) {
21
+ console.error("ref argument is missing");
22
+ console.error("Usage: npm-version-script.js <ref> [tag]");
23
+ process.exit(1);
24
+ }
25
+
26
+ /**
27
+ * Queries the NPM registry for the latest version for the provided tag.
28
+ * @param tag The tag to query for.
29
+ * @returns {string} Returns the version.
30
+ */
31
+ function getTagVersionFromNpm(tag) {
32
+ try {
33
+ return child_process.execSync(`npm info ${packageJSON.name} version --tag="${tag}"`).toString("utf8").trim();
34
+ } catch (e) {
35
+ console.error(`Failed to query the npm registry for the latest version for tag: ${tag}`);
36
+ // throw e;
37
+ return "0.0.0";
38
+ }
39
+ }
40
+
41
+ function desiredTargetVersion(ref) {
42
+ // ref is a GitHub action ref string
43
+ if (ref.startsWith("refs/pull/")) {
44
+ throw Error("The version script was executed inside a PR!");
45
+ }
46
+
47
+ assert(ref.startsWith("refs/heads/"))
48
+ let branchName = ref.slice("refs/heads/".length);
49
+
50
+ let results = branchName.match(BRANCH_VERSION_PATTERN);
51
+ if (results != null) {
52
+ if (results[1] !== tagArgument) {
53
+ console.warn(`The base branch name (${results[1]}) differs from the tag name ${tagArgument}`);
54
+ }
55
+
56
+ return results[2];
57
+ }
58
+
59
+ // legacy mode were we use the `betaVersion` property in the package.json
60
+ if (branchName === "beta" && packageJSON.betaVersion) {
61
+ return packageJSON.betaVersion
62
+ }
63
+
64
+ // legacy mode were we use the `alphaVersion` property in the package.json
65
+ if (branchName === "alpha" && packageJSON.alphaVersion) {
66
+ return packageJSON.alphaVersion
67
+ }
68
+
69
+ throw new Error(`Malformed branch name for ref: ${ref}. Can't derive the base version. Use a branch name like: beta-x.x.x or alpha-x.x.x`);
70
+ }
71
+
72
+ // derive the base version from the branch ref
73
+ const baseVersion = desiredTargetVersion(refArgument);
74
+
75
+ // query the npm registry for the latest version of the provided tag name
76
+ const latestReleasedVersion = getTagVersionFromNpm(tagArgument); // e.g. 0.7.0-beta.12
77
+ const latestReleaseBase = semver.inc(latestReleasedVersion, "patch"); // will produce 0.7.0 (removing the preid, needed for the equality check below)
78
+
79
+ let publishTag;
80
+ if (semver.eq(baseVersion, latestReleaseBase)) { // check if we are releasing another version for the latest beta or alpha
81
+ publishTag = latestReleasedVersion; // set the current latest beta or alpha to be incremented
82
+ } else {
83
+ publishTag = baseVersion; // start of with a new beta or alpha version
84
+ }
85
+
86
+ // save the package.json
87
+ packageJSON.version = publishTag;
88
+ fs.writeFileSync("package.json", JSON.stringify(packageJSON, null, 2));
89
+
90
+ // perform the same change to the package-lock.json
91
+ const packageLockJSON = JSON.parse(fs.readFileSync("package-lock.json", "utf8"));
92
+ packageLockJSON.version = publishTag;
93
+ fs.writeFileSync("package-lock.json", JSON.stringify(packageLockJSON, null, 2));
@@ -0,0 +1,119 @@
1
+ name: "Build, Publish and Release"
2
+
3
+ #
4
+ # Automatically publish beta releases on pushes, require a manual workflow action for production releases
5
+ #
6
+ # Does the following
7
+ # 1 - Run the documentation script against the package
8
+ # 2 - Create the npm package using the package.json version tag ( or for beta releases, adds a beta tag and increments as needed )
9
+ # 3 - Publish the npm package
10
+ # 4 - For releases against the main branch, create a github release as well
11
+
12
+ on:
13
+ push:
14
+ branches: [beta-*.*.*, beta]
15
+ workflow_dispatch:
16
+
17
+ jobs:
18
+ get_tags:
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ # checkout repo
23
+ - uses: actions/checkout@v4
24
+
25
+ # get branch / tag name
26
+ - name: Get Branch / Tag Name
27
+ id: get_branch
28
+ run: |
29
+ export BRANCH_NAME=$(if [[ ${GITHUB_REF} =~ "refs/tags/" ]]; then echo ${GITHUB_REF/refs\/tags\//}; else echo ${GITHUB_REF/refs\/heads\//}; fi)
30
+ echo $BRANCH_NAME
31
+ echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_OUTPUT
32
+
33
+ # generate the image tag
34
+ - name: Get Image Tag
35
+ id: get_tag
36
+ run: |
37
+ export TARGET_IMAGE_TAG=$(if [ "${{ steps.get_branch.outputs.BRANCH_NAME }}" = "main" ]; then echo "main"; else echo "${{ steps.get_branch.outputs.BRANCH_NAME }}" | awk -F- '{ print $1 }'; fi)
38
+ echo $TARGET_IMAGE_TAG
39
+ echo "TARGET_IMAGE_TAG=${TARGET_IMAGE_TAG}" >> $GITHUB_OUTPUT
40
+
41
+ outputs:
42
+ BRANCH_NAME: ${{ steps.get_branch.outputs.BRANCH_NAME }}
43
+ TARGET_IMAGE_TAG: ${{ steps.get_tag.outputs.TARGET_IMAGE_TAG }}
44
+
45
+ create_documentation:
46
+ runs-on: ubuntu-latest
47
+
48
+ steps:
49
+ # checkout repo
50
+ - uses: actions/checkout@v4
51
+ with:
52
+ persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
53
+ fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
54
+
55
+ - uses: actions/setup-node@v4
56
+ with:
57
+ node-version: lts/*
58
+
59
+ - name: Retrieve github-markdown-toc
60
+ run: |
61
+ wget -q https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc
62
+ chmod a+x gh-md-toc
63
+
64
+ - name: Create Table of Contents
65
+ run: |
66
+ npm run-script document --if-present
67
+ rm gh-md-toc
68
+
69
+ - name: Commit files
70
+ run: |
71
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
72
+ git config --local user.name "github-actions[bot]"
73
+ git add *
74
+ git commit -a -m "Update TOC" || true
75
+
76
+ - name: Push changes
77
+ uses: ad-m/github-push-action@master
78
+ with:
79
+ github_token: ${{ secrets.GITHUB_TOKEN }}
80
+ branch: ${{ github.ref }}
81
+
82
+ publish_prod_release:
83
+ needs: [get_tags, create_documentation]
84
+ name: Publish Release Version
85
+ if: ${{ needs.get_tags.outputs.BRANCH_NAME == 'main' }}
86
+ uses: homebridge/.github/.github/workflows/npm-publish.yml@latest
87
+ with:
88
+ install_cmd: npm ci
89
+ secrets:
90
+ npm_auth_token: ${{ secrets.npm_token }}
91
+
92
+ publish_test_release:
93
+ needs: [get_tags, create_documentation]
94
+ name: Publish Test Version - ${{ needs.get_tags.outputs.BRANCH_NAME }}
95
+ if: ${{ needs.get_tags.outputs.BRANCH_NAME != 'main' }}
96
+ uses: homebridge/.github/.github/workflows/npm-publish.yml@latest
97
+ with:
98
+ tag: ${{ needs.get_tags.outputs.TARGET_IMAGE_TAG }}
99
+ dynamically_adjust_version: true
100
+ npm_version_command: 'pre'
101
+ pre_id: ${{ needs.get_tags.outputs.TARGET_IMAGE_TAG }}
102
+ secrets:
103
+ npm_auth_token: ${{ secrets.npm_token }}
104
+
105
+ publish_github_release:
106
+ needs: [publish_prod_release]
107
+ runs-on: ubuntu-latest
108
+ steps:
109
+ - uses: actions/checkout@v4
110
+ - name: Create Release
111
+ uses: softprops/action-gh-release@v1
112
+ env:
113
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
114
+ with:
115
+ tag_name: ${{ needs.publish_prod_release.outputs.NPM_VERSION }}
116
+ name: Release ${{ needs.publish_prod_release.outputs.NPM_VERSION }}
117
+ generate_release_notes: true
118
+ draft: false
119
+ prerelease: false
package/README.md CHANGED
@@ -60,7 +60,7 @@ The above Node-RED Flow, turns on my 'Outside Office' light when the powder room
60
60
  * [To start Node-RED in DEBUG mode, and output Homebridge-Automation debug logs start Node-RED like this.](#to-start-node-red-in-debug-mode-and-output-homebridge-automation-debug-logs-start-node-red-like-this)
61
61
 
62
62
  <!-- Created by https://github.com/ekalinin/github-markdown-toc -->
63
- <!-- Added by: sgracey, at: Sun 19 Mar 2023 11:30:14 EDT -->
63
+ <!-- Added by: runner, at: Fri Jul 5 02:40:07 UTC 2024 -->
64
64
 
65
65
  <!--te-->
66
66
 
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "node-red-contrib-homebridge-automation",
3
- "version": "0.1.11",
3
+ "version": "0.1.12-beta.0",
4
4
  "description": "NodeRED Automation for HomeBridge",
5
- "main": "HAP-NodeRed.js",
5
+ "main": "src/HAP-NodeRed.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1",
8
8
  "api": "documentation build HAP-NodeRed.js -f md --config docs/documentation.yml > docs/API.md",
9
- "document": "./gh-md-toc --insert README.md; rm README.md.orig.* README.md.toc.*"
9
+ "document": "./gh-md-toc --insert README.md; rm README.md.orig.* README.md.toc.*",
10
+ "watch": "nodemon"
10
11
  },
11
12
  "keywords": [
12
13
  "node-red",
@@ -14,7 +15,7 @@
14
15
  ],
15
16
  "node-red": {
16
17
  "nodes": {
17
- "HAP-NodeRed": "HAP-NodeRed.js"
18
+ "HAP-NodeRed": "src/HAP-NodeRed.js"
18
19
  }
19
20
  },
20
21
  "repository": {
@@ -22,17 +23,31 @@
22
23
  "url": "git+https://github.com/NorthernMan54/node-red-contrib-homebridge-automation.git"
23
24
  },
24
25
  "devDependencies": {
25
- "documentation": "^14.0.1"
26
+ "documentation": "^14.0.3",
27
+ "nodemon": "^3.1.4",
28
+ "semver": "^7.6.2"
26
29
  },
27
30
  "dependencies": {
28
31
  "better-queue": ">=3.8.12",
29
- "debug": "^4.3.4",
30
- "hap-node-client": ">=0.2.4"
32
+ "debug": "^4.3.5",
33
+ "hap-node-client": ">=0.2.7"
31
34
  },
32
35
  "author": "NorthernMan54",
33
36
  "license": "ISC",
34
37
  "bugs": {
35
38
  "url": "https://github.com/NorthernMan54/node-red-contrib-homebridge-automation/issues"
36
39
  },
37
- "homepage": "https://github.com/NorthernMan54/node-red-contrib-homebridge-automation#readme"
40
+ "homepage": "https://github.com/NorthernMan54/node-red-contrib-homebridge-automation#readme",
41
+ "nodemonConfig": {
42
+ "watch": [
43
+ "src"
44
+ ],
45
+ "ext": "js,html",
46
+ "ignore": [],
47
+ "exec": "DEBUG=hapNodeRed ~/npm/bin/node-red",
48
+ "signal": "SIGTERM",
49
+ "env": {
50
+ "NODE_OPTIONS": "--trace-warnings"
51
+ }
52
+ }
38
53
  }
@@ -504,17 +504,42 @@ module.exports = function (RED) {
504
504
  var node = this;
505
505
 
506
506
  node.on('input', function (msg) {
507
- const payload = {};
508
507
  this.msg = msg;
509
- Object.keys(msg.payload).sort().forEach(function (key) {
510
- payload[key] = msg.payload[key];
511
- });
512
- _control.call(this, node, msg.payload, function (err, data) {
508
+ var device;
509
+
510
+ try {
511
+ if (msg.name) {
512
+ device = hbDevices.findDeviceByName(msg.name, {
513
+ perms: 'pw'
514
+ });
515
+ } else {
516
+ device = hbDevices.findDevice(node.device, {
517
+ perms: 'pw'
518
+ });
519
+ }
520
+ } catch (err) {
521
+ var error = "Homebridge not initialized";
522
+ node.status({
523
+ text: error,
524
+ shape: 'ring',
525
+ fill: 'red'
526
+ });
527
+ node.error(error, this.msg);
528
+ return;
529
+ }
530
+
531
+ _control.call(this, node, device, msg.payload, function (err, data) {
513
532
  // debug('hbControl [%s] - [%s]', err, data); // Images produce alot of noise
514
- if (err) {
533
+ if (!err && data && (device.type == '00000110' || device.type == '00000111')) {
534
+ // debug('hbControl', err, data); // Images produce alot of noise
535
+ const msg = {};
536
+ msg.payload = data;
537
+ node.send(msg);
538
+ } else {
515
539
  node.error(err, this.msg);
516
540
  }
517
541
  }.bind(this));
542
+
518
543
  });
519
544
 
520
545
  node.on('close', function (callback) {
@@ -525,9 +550,10 @@ module.exports = function (RED) {
525
550
  // debug("hbControl.register:", node.fullName, node);
526
551
  switch (node.service) {
527
552
  case "Camera Control": // Camera Control
528
- // debug("hbControl camera");
553
+ debug("hbControl camera");
529
554
  break;
530
555
  default:
556
+ debug("node.conf.register", node.service);
531
557
  }
532
558
  });
533
559
  }
@@ -573,7 +599,7 @@ module.exports = function (RED) {
573
599
  perms: 'pr'
574
600
  }, function (err, message) {
575
601
  if (!err) {
576
- debug("hbStatus received: %s = %s", JSON.stringify(node.fullName), JSON.stringify(message));
602
+ debug("hbStatus received: %s = %s", JSON.stringify(node.fullName), JSON.stringify(message), JSON.stringify(node.hbDevice));
577
603
  this.msg.name = node.name;
578
604
  this.msg._rawMessage = message;
579
605
  this.msg.payload = _convertHBcharactericToNode(message.characteristics, node);
@@ -581,7 +607,7 @@ module.exports = function (RED) {
581
607
  if (node.hbDevice) {
582
608
  this.msg.Homebridge = node.hbDevice.homebridge;
583
609
  this.msg.Manufacturer = node.hbDevice.manufacturer;
584
- this.msg.Service = node.hbDevice.deviceType;
610
+ this.msg.Service = node.hbDevice.service;
585
611
  this.msg._device = node.device;
586
612
  this.msg._confId = node.confId;
587
613
  }
@@ -630,10 +656,10 @@ module.exports = function (RED) {
630
656
  });
631
657
 
632
658
  RED.httpAdmin.get('/hap-device/evDevices/:id', RED.auth.needsPermission('hb-event.read'), function (req, res) {
633
- debug("evDevices", hbDevices.toList({
634
- perms: 'ev'
635
- }).length);
636
659
  if (evDevices) {
660
+ debug("evDevices", hbDevices.toList({
661
+ perms: 'ev'
662
+ }).length);
637
663
  res.send(hbDevices.toList({
638
664
  perms: 'ev'
639
665
  }));
@@ -800,11 +826,11 @@ module.exports = function (RED) {
800
826
  "image-width": 1920,
801
827
  "image-height": 1080
802
828
  };
803
- debug("Control %s:%s ->", device.host, device.port, JSON.stringify(message));
804
- homebridge.HAPresource(device.host, device.port, JSON.stringify(message), function (err, status) {
805
- // debug("status", btoa(status));
829
+ debug("_status Control %s -> %s", device.id, JSON.stringify(message));
830
+ homebridge.HAPresourceByDeviceID(device.id, JSON.stringify(message), function (err, status) {
831
+ debug("status", err);
806
832
  if (!err) {
807
- debug("Controlled %s:%s ->", device.host, device.port);
833
+ debug("_status Controlled %s:%s ->", device.host, device.port);
808
834
  node.status({
809
835
  text: 'sent',
810
836
  shape: 'dot',
@@ -868,6 +894,7 @@ module.exports = function (RED) {
868
894
  callback(error);
869
895
  } // end of device if
870
896
  } catch (err) {
897
+ debug('_status', err);
871
898
  error = "Homebridge not initialized";
872
899
  node.status({
873
900
  text: error,
@@ -888,11 +915,8 @@ module.exports = function (RED) {
888
915
  * @return {type} description
889
916
  */
890
917
 
891
- function _control(node, payload, callback) {
918
+ function _control(node, device, payload, callback) {
892
919
  try {
893
- var device = hbDevices.findDevice(node.device, {
894
- perms: 'pw'
895
- });
896
920
  if (device) {
897
921
  var message;
898
922
  switch (device.type) {
@@ -907,6 +931,7 @@ module.exports = function (RED) {
907
931
  homebridge.HAPresourceByDeviceID(device.id, JSON.stringify(message), function (err, status) {
908
932
  if (!err) {
909
933
  debug("Controlled %s ->", device.id, JSON.stringify(payload));
934
+ debug("Payload %s ->", device.id, status);
910
935
  node.status({
911
936
  text: JSON.stringify(payload),
912
937
  shape: 'dot',
@@ -994,14 +1019,13 @@ module.exports = function (RED) {
994
1019
  }
995
1020
  } // End of switch
996
1021
  } else {
997
- var err = 'Device not available';
998
- node.error(err);
1022
+ var error = 'Device not available';
999
1023
  node.status({
1000
- text: err,
1024
+ text: error,
1001
1025
  shape: 'ring',
1002
1026
  fill: 'red'
1003
1027
  });
1004
- callback(err);
1028
+ callback(error);
1005
1029
  }
1006
1030
  } catch (err) {
1007
1031
  var error = "Homebridge not initialized";
@@ -23,8 +23,8 @@ function Accessory(devices, context) {
23
23
  case "0000003E": // Accessory Information
24
24
  this.info = information(element.characteristics);
25
25
  break;
26
- case "00000110": // Camera RTPStream Management generates duplicates
27
- break;
26
+ // case "00000110": // Camera RTPStream Management generates duplicates
27
+ // break;
28
28
  case "000000D9": // Input Source from webosTV has a dummy input source
29
29
  var service = new Service(element, this);
30
30
  if (service.name !== "dummy") {
@@ -56,3 +56,13 @@ Homebridges.prototype.findDevice = function(node, opt) {
56
56
  }
57
57
  return (list.find(x => x.uniqueId === node));
58
58
  };
59
+
60
+ Homebridges.prototype.findDeviceByName = function(name, opt) {
61
+ var list = [];
62
+ for (var index in this.homebridges) {
63
+ var homebridge = this.homebridges[index];
64
+ // list.push(homebridge.toList());
65
+ list = list.concat(homebridge.toList(opt));
66
+ }
67
+ return (list.find(x => x.name === name));
68
+ };
package/beta.sh DELETED
@@ -1,16 +0,0 @@
1
- #! /bin/sh
2
-
3
- npm audit
4
- npm audit fix
5
- #if npm audit; then
6
- npm run-script document
7
- rm *orig* *toc\.*
8
- git add .
9
- # npm version patch -m "$1" --force
10
- npm version prerelease --preid beta -m "$1" --force
11
- npm publish --tag beta
12
- git commit -m "$1"
13
- git push origin beta --tags
14
- #else
15
- # echo "Not publishing due to security vulnerabilites"
16
- #fi
package/example.js DELETED
@@ -1,83 +0,0 @@
1
- var Queue = require('better-queue');
2
-
3
- var q = new Queue(function(input, cb) {
4
- console.log('Loop', input);
5
- cb(null, input * -1);
6
- }, {
7
- concurrent: 3
8
- });
9
-
10
- for (var i = 0; i < 10; i++) {
11
- q.push(i, function(err, result) {
12
- console.log('Done', result);
13
- });
14
- }
15
-
16
-
17
-
18
- // add jobs using the familiar Array API
19
-
20
-
21
-
22
- /*
23
-
24
- q.push(
25
- function(cb) {
26
- results.push('four')
27
- cb()
28
- },
29
- function(cb) {
30
- results.push('five')
31
- cb()
32
- }
33
- )
34
-
35
- // jobs can accept a callback or return a promise
36
- q.push(function() {
37
- return new Promise(function(resolve, reject) {
38
- results.push('one')
39
- resolve()
40
- })
41
- })
42
-
43
- q.unshift(function(cb) {
44
- results.push('one')
45
- cb()
46
- })
47
-
48
- q.splice(2, 0, function(cb) {
49
- results.push('three')
50
- cb()
51
- })
52
-
53
- // use the timeout feature to deal with jobs that
54
- // take too long or forget to execute a callback
55
- q.timeout = 100
56
-
57
- q.on('timeout', function(next, job) {
58
- console.log('job timed out:', job.toString().replace(/\n/g, ''))
59
- next()
60
- })
61
-
62
- q.push(function(cb) {
63
- setTimeout(function() {
64
- console.log('slow job finished')
65
- cb()
66
- }, 200)
67
- })
68
-
69
- q.push(function(cb) {
70
- console.log('forgot to execute callback')
71
- })
72
-
73
- // get notified when jobs complete
74
- q.on('success', function(result, job) {
75
- console.log('job finished processing:', job.toString().replace(/\n/g, ''))
76
- })
77
-
78
- // begin processing, get notified on end / failure
79
- q.start(function(err) {
80
- if (err) throw err
81
- console.log('all done:', results)
82
- })
83
- */
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes