From 59f4fef2581ca82ba64d597d9433f1088dd531df Mon Sep 17 00:00:00 2001 From: Northern Man <19808920+NorthernMan54@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:12:52 -0500 Subject: [PATCH] Pre Update --- .github/workflows/Build and Publish.yml | 125 ++++++++++++++ .gitignore | 3 + eslint.config.mjs | 28 +++ package.json | 58 ++++++- publish.sh | 13 -- index.js => src/index.js | 218 ++++++++++++------------ {lib => src/lib}/util.js | 0 test/hbConfig/.uix-dashboard.json | 1 + test/hbConfig/.uix-secrets | 1 + test/hbConfig/auth.json | 10 ++ test/hbConfig/config.json | 37 ++++ 11 files changed, 364 insertions(+), 130 deletions(-) create mode 100644 .github/workflows/Build and Publish.yml create mode 100644 eslint.config.mjs delete mode 100755 publish.sh rename index.js => src/index.js (82%) rename {lib => src/lib}/util.js (100%) create mode 100644 test/hbConfig/.uix-dashboard.json create mode 100644 test/hbConfig/.uix-secrets create mode 100644 test/hbConfig/auth.json create mode 100644 test/hbConfig/config.json diff --git a/.github/workflows/Build and Publish.yml b/.github/workflows/Build and Publish.yml new file mode 100644 index 0000000..21d3812 --- /dev/null +++ b/.github/workflows/Build and Publish.yml @@ -0,0 +1,125 @@ +name: + 'Build, Publish and Release' + + # + # Automatically publish beta releases on pushes, require a manual workflow action for production releases + # + # Does the following + # 1 - Run the documentation script against the package + # 2 - Create the npm package using the package.json version tag ( or for beta releases, adds a beta tag and increments as needed ) + # 3 - Publish the npm package + # 4 - For releases against the latest branch, create a github release as well + +on: + push: + branches: [beta-*.*.*, beta] + workflow_dispatch: + +jobs: + get_tags: + runs-on: ubuntu-latest + + steps: + # checkout repo + - uses: actions/checkout@v4 + + # get branch / tag name + - name: Get Branch / Tag Name + id: get_branch + run: | + export BRANCH_NAME=$(if [[ ${GITHUB_REF} =~ "refs/tags/" ]]; then echo ${GITHUB_REF/refs\/tags\//}; else echo ${GITHUB_REF/refs\/heads\//}; fi) + echo $BRANCH_NAME + echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_OUTPUT + + # generate the image tag + - name: Get Image Tag + id: get_tag + run: | + 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) + echo $TARGET_IMAGE_TAG + echo "TARGET_IMAGE_TAG=${TARGET_IMAGE_TAG}" >> $GITHUB_OUTPUT + + outputs: + BRANCH_NAME: ${{ steps.get_branch.outputs.BRANCH_NAME }} + TARGET_IMAGE_TAG: ${{ steps.get_tag.outputs.TARGET_IMAGE_TAG }} + + create_documentation: + runs-on: ubuntu-latest + + steps: + # checkout repo + - uses: actions/checkout@v4 + with: + persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. + fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. + + - uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Retrieve github-markdown-toc + run: | + wget -q https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc + chmod a+x gh-md-toc + + - name: Create Table of Contents + run: | + npm run-script document --if-present + rm gh-md-toc + + - name: Commit files + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add * || true + git commit -a -m "Update TOC" || true + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ github.ref }} + + publish_prod_release: + permissions: + id-token: write + needs: [get_tags, create_documentation] + name: Publish Release Version + if: ${{ needs.get_tags.outputs.BRANCH_NAME == 'main' }} + uses: homebridge/.github/.github/workflows/npm-publish.yml@latest + with: + install_cmd: npm ci + secrets: + npm_auth_token: ${{ secrets.NPM_TOKEN }} + + publish_test_release: + permissions: + id-token: write + needs: [get_tags, create_documentation] + name: Publish Test Version - ${{ needs.get_tags.outputs.BRANCH_NAME }} + if: ${{ needs.get_tags.outputs.BRANCH_NAME != 'main' }} + uses: homebridge/.github/.github/workflows/npm-publish.yml@latest + with: + tag: ${{ needs.get_tags.outputs.TARGET_IMAGE_TAG }} + dynamically_adjust_version: true + npm_version_command: pre + pre_id: ${{ needs.get_tags.outputs.TARGET_IMAGE_TAG }} + install_cmd: npm ci + secrets: + npm_auth_token: ${{ secrets.NPM_TOKEN }} + + publish_github_release: + needs: [publish_prod_release] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Create Release + uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ needs.publish_prod_release.outputs.NPM_VERSION }} + name: Release ${{ needs.publish_prod_release.outputs.NPM_VERSION }} + generate_release_notes: true + draft: false + prerelease: false diff --git a/.gitignore b/.gitignore index 5bcc1aa..e59d08c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ package-lock.json # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules .DS_Store +/test/hbConfig/accessories +/test/hbConfig/backups +/test/hbConfig/persist diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..eb5fcc4 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,28 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import pluginJest from "eslint-plugin-jest"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { + files: ["**/*.js"], + languageOptions: { + sourceType: "commonjs", // Change to "module" for ES6 + globals: { + ...globals.browser, + ...globals.es2021, + ...globals.jest, // Add Jest globals + }, + }, + }, + pluginJs.configs.recommended, + { + plugins: { + jest: pluginJest, + }, + rules: { + ...pluginJest.configs.recommended.rules, + "no-unused-vars": "warn", // Change no-unused-vars to a warning + }, + }, +]; \ No newline at end of file diff --git a/package.json b/package.json index 1940889..05d6dbc 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,14 @@ { "name": "homebridge-yamaha-zone-tv", - "version": "0.1.23", - "description": "homebridge-plugin for Yamaha AVR https://github.com/nfarina/homebridge", - "main": "index.js", + "version": "0.2.0", + "description": "Control your Yamaha AVR with Homebridge", + "main": "src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "lint": "eslint --max-warnings=0 .", + "lint:fix": "eslint --fix --max-warnings=0 .", + "watch": "nodemon", + "test": "jest --detectOpenHandles", + "test-coverage": "jest --coverage" }, "repository": { "type": "git", @@ -17,8 +21,8 @@ "Yamaha" ], "engines": { - "node": ">=9.3.0", - "homebridge": ">=0.4.48" + "homebridge": "^1.6.0 || ^2.0.0-beta.0", + "node": "^18.20.4 || ^20.15.1 || ^22.0.0" }, "dependencies": { "bonjour": "^=3.5.0", @@ -31,10 +35,48 @@ "util": "^0.12.0", "yamaha-nodejs": "^0.9.1" }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "eslint": "^8.57.1", + "eslint-plugin-format": "^0.1.2", + "eslint-plugin-jest": "^28.8.3", + "globals": "^15.12.0", + "jest": "^29.7.0", + "nodemon": "^3.1.7" + }, "author": "NorthernMan54", "license": "ISC", "bugs": { "url": "https://github.com/NorthernMan54/homebridge-yamaha-zone-tv/issues" }, - "homepage": "https://github.com/NorthernMan54/homebridge-yamaha-zone-tv#readme" -} + "homepage": "https://github.com/NorthernMan54/homebridge-yamaha-zone-tv#readme", + "nodemonConfig": { + "watch": [ + "src" + ], + "ext": "js,cjs,mjs,json", + "ignore": [ + "**/*.spec.js", + "**/*.test.js" + ], + "exec": "DEBUG=yamaha*,Yamaha*- ~/npm/bin/homebridge -U ./test/hbConfig -I -T -D -P .", + "signal": "SIGTERM", + "env": { + "NODE_OPTIONS": "--trace-warnings" + } + }, + "jest": { + "testEnvironment": "node", + "modulePathIgnorePatterns": [], + "coverageReporters": [ + "lcov" + ], + "collectCoverageFrom": [ + "src/**", + "!src/accessories/**", + "!src/lib/definitions/generate-definitions.ts", + "!src/lib/definitions/generator-configuration.ts", + "!src/test-utils" + ] + } +} \ No newline at end of file diff --git a/publish.sh b/publish.sh deleted file mode 100755 index 047a267..0000000 --- a/publish.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/sh - -if npm audit; then -# rm *orig* *toc\.* -# npm run-script document - git add . - npm version patch -m "$1" --force - npm publish - git commit -m "$1" - git push origin master --tags -else - echo "Not publishing due to security vulnerabilites" -fi diff --git a/index.js b/src/index.js similarity index 82% rename from index.js rename to src/index.js index bd63458..afff1e4 100644 --- a/index.js +++ b/src/index.js @@ -29,7 +29,7 @@ var tvAccessories = []; var cachedAccessories = []; var controlAccessory; -module.exports = function(homebridge) { +module.exports = function (homebridge) { Accessory = homebridge.platformAccessory; Service = homebridge.hap.Service; hap = homebridge.hap; @@ -58,21 +58,21 @@ function YamahaAVRPlatform(log, config, api) { try { cachedConfig = JSON.parse(fs.readFileSync(CachedConfigFile)); } catch (err) { - debug('Cached names file does not exist'); - cachedConfig = { - custom: { - disablePartySwitch: undefined, - disableMainPowerSwitch: undefined, - radioPresets: undefined, - }, - units: {} - }; + debug('Cached names file does not exist'); + cachedConfig = { + custom: { + disablePartySwitch: undefined, + disableMainPowerSwitch: undefined, + radioPresets: undefined, + }, + units: {} + }; } this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this)); } -YamahaAVRPlatform.prototype.configureAccessory = function(accessory) { +YamahaAVRPlatform.prototype.configureAccessory = function (accessory) { debug("configuredAccessory", accessory); var foundDuplicateIndex = cachedAccessories.findIndex(cachedAccessory => cachedAccessory.UUID === accessory.UUID) @@ -85,7 +85,7 @@ YamahaAVRPlatform.prototype.configureAccessory = function(accessory) { }; -YamahaAVRPlatform.prototype.didFinishLaunching = function() { +YamahaAVRPlatform.prototype.didFinishLaunching = function () { debug('didFinishLaunching') this.log("Getting Yamaha AVR devices."); var that = this; @@ -106,7 +106,7 @@ YamahaAVRPlatform.prototype.didFinishLaunching = function() { }); } - setTimeout(function() { + setTimeout(function () { that.log("Waited " + that.discoveryTimeout + " seconds, stopping discovery."); browser.stop(); @@ -115,23 +115,23 @@ YamahaAVRPlatform.prototype.didFinishLaunching = function() { // debug('PLATFORM - cachedAccessories', cachedAccessories) - if ( cachedConfig.custom.radioPresets === undefined + if (cachedConfig.custom.radioPresets === undefined || cachedConfig.custom.radioPresets !== that.radioPresets || cachedConfig.custom.disablePartySwitch !== that.disablePartySwitch - || cachedConfig.custom.disableMainPowerSwitch !== that.disableMainPowerSwitch){ + || cachedConfig.custom.disableMainPowerSwitch !== that.disableMainPowerSwitch) { - cachedConfig.custom["radioPresets"] = that.radioPresets; - cachedConfig.custom["disablePartySwitch"] = that.disablePartySwitch; - cachedConfig.custom["disableMainPowerSwitch"] = that.disableMainPowerSwitch; + cachedConfig.custom["radioPresets"] = that.radioPresets; + cachedConfig.custom["disablePartySwitch"] = that.disablePartySwitch; + cachedConfig.custom["disableMainPowerSwitch"] = that.disableMainPowerSwitch; - fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { - if (err) - debug('Error occured could not write cachedConfig file %s', err); - }); + fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { + if (err) + debug('Error occured could not write cachedConfig file %s', err); + }); - debug('UNREGISTERING - cachedAccessories') - that.api.unregisterPlatformAccessories("homebridge-yamaha-zone-tv", "yamaha-zone-tv", cachedAccessories); - cachedAccessories = []; + debug('UNREGISTERING - cachedAccessories') + that.api.unregisterPlatformAccessories("homebridge-yamaha-zone-tv", "yamaha-zone-tv", cachedAccessories); + cachedAccessories = []; } if (controlAccessory && !cachedAccessories.find(accessory => accessory.UUID === controlAccessory.UUID)) { @@ -165,7 +165,7 @@ function setupFromService(service) { var yamaha = new Yamaha(service.host); yamaha.getSystemConfig().then( - function(sysConfig) { + function (sysConfig) { // debug(JSON.stringify(sysConfig, null, 2)); if (sysConfig && sysConfig.YAMAHA_AV) { var sysModel = sysConfig.YAMAHA_AV.System[0].Config[0].Model_Name[0]; @@ -192,7 +192,7 @@ function setupFromService(service) { for (var prop in inputsXML) { // iterate through all inputs - var inputName =util.syncName(prop) + var inputName = util.syncName(prop) var input = util.getInputConfig(inputName) @@ -217,7 +217,7 @@ function setupFromService(service) { // Only return inputs that the receiver supports, skip Zone entries and USB since it's already in the input list if (!(prop.includes('one')) && !(prop.includes('USB')) && zonesXML[prop].includes('1')) { - var inputName =util.syncName(prop) + var inputName = util.syncName(prop) var input = util.getInputConfig(inputName) @@ -237,7 +237,7 @@ function setupFromService(service) { } yamaha.getAvailableZones().then( - function(zones) { + function (zones) { if (zones.length > 0) { if (!this.disableMainPowerSwitch || !this.disablePartySwitch || this.radioPresets) @@ -246,10 +246,10 @@ function setupFromService(service) { controlAccessory = null // if there is no need to create an extra switch for (var zone in zones) { - yamaha.getBasicInfo(zones[zone]).then(function(basicInfo) { + yamaha.getBasicInfo(zones[zone]).then(function (basicInfo) { if (basicInfo.getVolume() !== -999) { yamaha.getZoneConfig(basicInfo.getZone()).then( - function(zoneInfo) { + function (zoneInfo) { if (zoneInfo) { var zoneId = Object.keys(zoneInfo.YAMAHA_AV)[1]; var zoneName = zoneInfo.YAMAHA_AV[zoneId][0].Config[0].Name[0].Zone[0]; @@ -276,7 +276,7 @@ function setupFromService(service) { fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { if (err) - debug('Error occured could not write cachedConfig file %s', err); + debug('Error occured could not write cachedConfig file %s', err); }); } @@ -290,7 +290,7 @@ function setupFromService(service) { ); } }.bind(this), - function(error) { + function (error) { this.log("DEBUG: Failed getSystemConfig from " + name + ", probably just not a Yamaha AVR."); }.bind(this) ); @@ -320,13 +320,13 @@ function YamahaZone(log, config, name, yamaha, sysConfig, zoneId, accessory, uni YamahaZone.prototype = { - setPlaying: function(playing) { + setPlaying: function (playing) { var that = this; var yamaha = this.yamaha; if (playing) { - return yamaha.powerOn(that.zone).then(function() { - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + return yamaha.powerOn(that.zone).then(function () { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { if (basicInfo.getCurrentInput() === 'AirPlay' || basicInfo.getCurrentInput() === 'Spotify') { var input = basicInfo.getCurrentInput(); return yamaha.SendXMLToReceiver( @@ -342,7 +342,7 @@ YamahaZone.prototype = { } }, - getServices: function() { + getServices: function () { var that = this; var yamaha = this.yamaha; @@ -352,7 +352,7 @@ YamahaZone.prototype = { .setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "yamaha-zone-tv") .setCharacteristic(Characteristic.Model, this.sysConfig.YAMAHA_AV.System[0].Config[0].Model_Name[0]) - .setCharacteristic(Characteristic.FirmwareRevision, require('./package.json').version) + .setCharacteristic(Characteristic.FirmwareRevision, require('../package.json').version) .setCharacteristic(Characteristic.SerialNumber, this.sysId + '_' + this.zone); // for main zone Only @@ -360,31 +360,31 @@ YamahaZone.prototype = { if (this.controlAccessory) { this.controlAccessory.getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.Name, this.unitName) - .setCharacteristic(Characteristic.Manufacturer, "yamaha-zone-tv") - .setCharacteristic(Characteristic.Model, this.sysConfig.YAMAHA_AV.System[0].Config[0].Model_Name[0]) - .setCharacteristic(Characteristic.FirmwareRevision, require('./package.json').version) - .setCharacteristic(Characteristic.SerialNumber, this.sysId); + .setCharacteristic(Characteristic.Name, this.unitName) + .setCharacteristic(Characteristic.Manufacturer, "yamaha-zone-tv") + .setCharacteristic(Characteristic.Model, this.sysConfig.YAMAHA_AV.System[0].Config[0].Model_Name[0]) + .setCharacteristic(Characteristic.FirmwareRevision, require('../package.json').version) + .setCharacteristic(Characteristic.SerialNumber, this.sysId); if (!this.disableMainPowerSwitch) { var mainSwitch = new Service.Switch("Main Power", UUIDGen.generate(this.sysId + 'Main Power'), this.sysId + 'Main Power'); mainSwitch .getCharacteristic(Characteristic.On) - .on('get', function(callback, context) { + .on('get', function (callback, context) { yamaha.isOn().then( - function(result) { + function (result) { debug("Main Power", result); callback(null, result); }, - function(error) { + function (error) { callback(error, false); } ); }) - .on('set', function(powerOn, callback) { - this.setPlaying(powerOn).then(function() { + .on('set', function (powerOn, callback) { + this.setPlaying(powerOn).then(function () { callback(null); - }, function(error) { + }, function (error) { callback(error); // TODO: Actually determine and send real new status. }); }.bind(this)); @@ -397,23 +397,23 @@ YamahaZone.prototype = { var partySwitch = new Service.Switch("Party", UUIDGen.generate("Party"), "Party"); partySwitch .getCharacteristic(Characteristic.On) - .on('get', function(callback) { - this.yamaha.isPartyModeEnabled().then(function(result) { + .on('get', function (callback) { + this.yamaha.isPartyModeEnabled().then(function (result) { debug("getPartySwitch", that.zone, result); callback(null, result); }); }.bind(this)) - .on('set', function(on, callback) { + .on('set', function (on, callback) { debug("setPartySwitch", that.zone, on); if (on) { const that = this; - this.yamaha.powerOn().then(function() { - that.yamaha.partyModeOn().then(function() { + this.yamaha.powerOn().then(function () { + that.yamaha.partyModeOn().then(function () { callback(null); }); }); } else { - this.yamaha.partyModeOff().then(function() { + this.yamaha.partyModeOff().then(function () { callback(null); }); } @@ -424,7 +424,7 @@ YamahaZone.prototype = { // Radio Preset buttons if (this.radioPresets) { - yamaha.getTunerPresetList().then(function(presets) { + yamaha.getTunerPresetList().then(function (presets) { for (var preset in presets) { this.log("Adding preset %s - %s", preset, presets[preset].value, this.presetNum); if (!this.presetNum) { @@ -439,14 +439,14 @@ YamahaZone.prototype = { presetSwitch.context.preset = preset; presetSwitch .getCharacteristic(Characteristic.On) - .on('get', function(callback, context) { + .on('get', function (callback, context) { // debug("getPreset", this); - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { // debug('YamahaSwitch Is On', basicInfo.isOn()); // True // debug('YamahaSwitch Input', basicInfo.getCurrentInput()); // Tuner if (basicInfo.isOn() && basicInfo.getCurrentInput() === 'TUNER') { - yamaha.getTunerInfo().then(function(result) { + yamaha.getTunerInfo().then(function (result) { // console.log( 'TunerInfo', JSON.stringify(result,null, 0)); debug(result.Play_Info[0].Feature_Availability[0]); // Ready debug(result.Play_Info[0].Search_Mode[0]); // Preset @@ -463,14 +463,14 @@ YamahaZone.prototype = { // Off callback(null, false); } - }.bind(this), function(error) { + }.bind(this), function (error) { callback(error); }); }.bind(presetSwitch)) - .on('set', function(powerOn, callback) { + .on('set', function (powerOn, callback) { // debug("setPreset", this); - yamaha.setMainInputTo("TUNER").then(function() { - return yamaha.selectTunerPreset(this.context.preset).then(function() { + yamaha.setMainInputTo("TUNER").then(function () { + return yamaha.selectTunerPreset(this.context.preset).then(function () { debug('Tuning radio to preset %s - %s', this.context.preset); callback(null); }.bind(this)); @@ -490,68 +490,68 @@ YamahaZone.prototype = { zoneService.getCharacteristic(Characteristic.ConfiguredName) .on('set', (name, callback) => { - debug('Setting new ConfiguredName for %s', this.zone ) + debug('Setting new ConfiguredName for %s', this.zone) cachedConfig.units[this.sysId].zones[this.zone].name = name fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { if (err) - debug('Error occured could not write cachedConfig file %s', err); + debug('Error occured could not write cachedConfig file %s', err); }); callback(null) }).updateValue(this.name) zoneService.getCharacteristic(Characteristic.Active) - .on('get', function(callback, context) { + .on('get', function (callback, context) { yamaha.isOn(that.zone).then( - function(result) { + function (result) { debug("getActive", that.zone, result); callback(null, result); }, - function(error) { + function (error) { debug("getActive - error", that.zone, error); callback(error); } ); }) - .on('set', function(powerOn, callback) { + .on('set', function (powerOn, callback) { debug("setActive", that.zone, powerOn); - this.setPlaying(powerOn).then(function() { + this.setPlaying(powerOn).then(function () { callback(null); - }, function(error) { + }, function (error) { callback(error); // TODO: Actually determine and send real new status. }); }.bind(this)); // Populate ActiveIdentifier with current input selection - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { debug('YamahaSwitch Is On', that.zone, basicInfo.isOn()); // True debug('YamahaSwitch Input', that.zone, basicInfo.getCurrentInput()); // Set identifier for active input - zoneService.getCharacteristic(Characteristic.ActiveIdentifier).updateValue(that.inputs.find(function(input) { + zoneService.getCharacteristic(Characteristic.ActiveIdentifier).updateValue(that.inputs.find(function (input) { return (input.NameIdentifier === basicInfo.getCurrentInput() ? input : false); }).Identifier); }); zoneService .getCharacteristic(Characteristic.ActiveIdentifier) - .on('get', function(callback) { + .on('get', function (callback) { // debug("getActiveIdentifier", that.zone); - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { debug("getActiveIdentifier Input", that.zone, basicInfo.getCurrentInput()); - callback(null, that.inputs.find(function(input) { + callback(null, that.inputs.find(function (input) { return (input.NameIdentifier === basicInfo.getCurrentInput() ? input : false); }).Identifier); }); // callback(null); }) - .on('set', function(newValue, callback) { + .on('set', function (newValue, callback) { debug("setActiveIdentifier => setNewValue: ", that.zone, newValue); - yamaha.setInputTo(that.inputs.find(function(input) { + yamaha.setInputTo(that.inputs.find(function (input) { debug("find %s === %s", input.Identifier, newValue); return (input.Identifier === newValue ? input : false); - }).NameIdentifier, that.zone).then(function(a, b) { + }).NameIdentifier, that.zone).then(function (a, b) { debug("setActiveIdentifier", that.zone, a, b); callback(null); }); @@ -560,7 +560,7 @@ YamahaZone.prototype = { zoneService .getCharacteristic(Characteristic.RemoteKey) - .on('set', function(newValue, callback) { + .on('set', function (newValue, callback) { debug("setRemoteKey: ", that.zone, newValue); if (this.cursorRemoteControl) { switch (newValue) { @@ -586,7 +586,7 @@ YamahaZone.prototype = { yamaha.remoteMenu("On Screen"); break; case Characteristic.RemoteKey.PLAY_PAUSE: - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { basicInfo.isMuted(that.zone) ? yamaha.muteOff(that.zone) : yamaha.muteOn(that.zone); }); break; @@ -596,7 +596,7 @@ YamahaZone.prototype = { var option = util.mapKeyToControl(newValue); if (option) { debug("command", that.zone, newValue, option, this.pausePlay); - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { if (basicInfo.getCurrentInput() === 'AirPlay' || basicInfo.getCurrentInput() === 'Spotify') { var input = basicInfo.getCurrentInput(); yamaha.SendXMLToReceiver( @@ -621,43 +621,43 @@ YamahaZone.prototype = { zoneService .getCharacteristic(Characteristic.CurrentMediaState) - .on('get', function(callback) { + .on('get', function (callback) { debug("getCurrentMediaState", that.zone); callback(null, Characteristic.CurrentMediaState.STOP); }) - .on('set', function(newValue, callback) { + .on('set', function (newValue, callback) { debug("setCurrentMediaState => setNewValue: " + newValue); callback(null); }); zoneService .getCharacteristic(Characteristic.TargetMediaState) - .on('get', function(callback) { + .on('get', function (callback) { debug("getTargetMediaState", that.zone); callback(null, Characteristic.TargetMediaState.STOP); }) - .on('set', function(newValue, callback) { + .on('set', function (newValue, callback) { debug("setTargetMediaState => setNewValue: ", that.zone, newValue); callback(null); }); zoneService .getCharacteristic(Characteristic.PictureMode) - .on('set', function(newValue, callback) { + .on('set', function (newValue, callback) { debug("setPictureMode => setNewValue: ", that.zone, newValue); callback(null); }); zoneService .getCharacteristic(Characteristic.PowerModeSelection) - .on('set', function(newValue, callback) { + .on('set', function (newValue, callback) { debug("setPowerModeSelection => setNewValue: ", that.zone, newValue); callback(null); }); this.accessory.addService(zoneService); - that.inputs.forEach(function(input) { + that.inputs.forEach(function (input) { // Don't add Main Zone Sync for the Main zone if (this.zone !== "Main_Zone" || input.NameIdentifier !== "Main Zone Sync") { // debug("Adding input", input.ConfiguredName, "for zone", this.name); @@ -665,12 +665,12 @@ YamahaZone.prototype = { inputService.getCharacteristic(Characteristic.ConfiguredName) .on('set', (name, callback) => { - debug('Setting new ConfiguredName for Input %s - %s', input.NameIdentifier, name ) + debug('Setting new ConfiguredName for Input %s - %s', input.NameIdentifier, name) cachedConfig.units[this.sysId].inputsNames[input.NameIdentifier] = name fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { if (err) - debug('Error occured could not write cachedConfig file %s', err); + debug('Error occured could not write cachedConfig file %s', err); }); // update each zone with the new configured input name @@ -692,18 +692,18 @@ YamahaZone.prototype = { .setCharacteristic(Characteristic.InputSourceType, input.InputSourceType) .setCharacteristic(Characteristic.InputDeviceType, input.InputDeviceType) .getCharacteristic(Characteristic.TargetVisibilityState) - .on('set', (newValue, callback) => { - debug("setTargetVisibilityState => setNewValue: ", that.zone, newValue); - inputService.getCharacteristic(Characteristic.CurrentVisibilityState).updateValue(newValue); - cachedConfig.units[this.sysId].zones[this.zone].hiddenInputs[input.NameIdentifier] = newValue - fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { - if (err) - debug('Error occured could not write cachedConfig file %s', err); - }); + .on('set', (newValue, callback) => { + debug("setTargetVisibilityState => setNewValue: ", that.zone, newValue); + inputService.getCharacteristic(Characteristic.CurrentVisibilityState).updateValue(newValue); + cachedConfig.units[this.sysId].zones[this.zone].hiddenInputs[input.NameIdentifier] = newValue + fs.writeFile(CachedConfigFile, JSON.stringify(cachedConfig), (err) => { + if (err) + debug('Error occured could not write cachedConfig file %s', err); + }); - callback(null); - }); + callback(null); + }); // check if VisibilityState is in cache var isHidden = cachedConfig.units[this.sysId].zones[this.zone].hiddenInputs[input.NameIdentifier] @@ -733,9 +733,9 @@ YamahaZone.prototype = { speakerService.getCharacteristic(Characteristic.Volume) - .on('get', function(callback) { + .on('get', function (callback) { debug("get Volume", that.zone); - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { var v = basicInfo.getVolume() / 10.0; var p = 100 * ((v - that.minVolume) / that.gapVolume); p = p < 0 ? 0 : p > 100 ? 100 : Math.round(p); @@ -743,18 +743,18 @@ YamahaZone.prototype = { callback(null, p); }); }) - .on('set', function(volume, callback) { + .on('set', function (volume, callback) { debug("set Volume => setNewValue: ", that.zone, volume); var v = ((volume / 100) * that.gapVolume) + that.minVolume; v = Math.round(v) * 10.0; debug("Setting volume to ", that.zone, v / 10); - yamaha.setVolumeTo(v, that.zone).then(function(status) { + yamaha.setVolumeTo(v, that.zone).then(function (status) { debug("Status", that.zone, status); }); callback(null); }); - yamaha.getBasicInfo(that.zone).then(function(basicInfo) { + yamaha.getBasicInfo(that.zone).then(function (basicInfo) { var v = basicInfo.getVolume() / 10.0; var p = 100 * ((v - that.minVolume) / that.gapVolume); p = p < 0 ? 0 : p > 100 ? 100 : Math.round(p); @@ -763,16 +763,16 @@ YamahaZone.prototype = { }); speakerService.getCharacteristic(Characteristic.VolumeSelector) - .on('set', function(decrement, callback) { + .on('set', function (decrement, callback) { if (decrement) { debug("Decrementing Volume by 1 for ", that.zone); - yamaha.volumeDown(10, that.zone).then(function(status) { + yamaha.volumeDown(10, that.zone).then(function (status) { debug("Status", that.zone, status); }); } else { debug("Incrementing Volume by 1 for ", that.zone); - yamaha.volumeUp(10, that.zone).then(function(status) { + yamaha.volumeUp(10, that.zone).then(function (status) { debug("Status", that.zone, status); }); } diff --git a/lib/util.js b/src/lib/util.js similarity index 100% rename from lib/util.js rename to src/lib/util.js diff --git a/test/hbConfig/.uix-dashboard.json b/test/hbConfig/.uix-dashboard.json new file mode 100644 index 0000000..f2c4361 --- /dev/null +++ b/test/hbConfig/.uix-dashboard.json @@ -0,0 +1 @@ +[{"component":"HomebridgeStatusWidgetComponent","x":0,"y":7,"cols":5,"rows":7,"mobileOrder":10,"hidePort":true,"hideOnMobile":false,"draggable":true},{"component":"ChildBridgeWidgetComponent","x":15,"y":9,"cols":5,"rows":5,"mobileOrder":35,"hideOnMobile":false,"draggable":true},{"component":"CpuWidgetComponent","x":5,"y":8,"cols":5,"rows":3,"mobileOrder":40,"hideOnMobile":false,"draggable":true},{"component":"MemoryWidgetComponent","x":5,"y":11,"cols":5,"rows":3,"mobileOrder":50,"hideOnMobile":false,"draggable":true},{"component":"NetworkWidgetComponent","x":10,"y":11,"cols":5,"rows":3,"mobileOrder":55,"hideOnMobile":false,"draggable":true},{"component":"UptimeWidgetComponent","x":10,"y":8,"cols":5,"rows":3,"mobileOrder":60,"hideOnMobile":false,"draggable":true},{"component":"SystemInfoWidgetComponent","x":15,"y":0,"cols":5,"rows":9,"mobileOrder":70,"hideOnMobile":false,"draggable":true},{"component":"HapQrcodeWidgetComponent","x":0,"y":0,"cols":5,"rows":7,"mobileOrder":100,"hideOnMobile":false,"draggable":true},{"component":"HomebridgeLogsWidgetComponent","x":5,"y":0,"cols":10,"rows":8,"mobileOrder":1000,"hideOnMobile":true,"draggable":true}] diff --git a/test/hbConfig/.uix-secrets b/test/hbConfig/.uix-secrets new file mode 100644 index 0000000..20a2581 --- /dev/null +++ b/test/hbConfig/.uix-secrets @@ -0,0 +1 @@ +{"secretKey":"de1a0f965770285a6dec91739fc725a91d6e0cb91a4aaae8116e8f140d44edc3"} diff --git a/test/hbConfig/auth.json b/test/hbConfig/auth.json new file mode 100644 index 0000000..8ae211f --- /dev/null +++ b/test/hbConfig/auth.json @@ -0,0 +1,10 @@ +[ + { + "id": 1, + "username": "test", + "name": "test", + "hashedPassword": "df121e72b850a058bd68f3d05b1f94dc985821a3885b5da38e263654f29843f98bb6d8e594f6042ff871a424602a9bff50dffa97f258bdc1dca4c79e87bac20c", + "salt": "64085e70da64670349f042d4c3d3cac75b20233ffeb71db68399973f60da077d", + "admin": true + } +] diff --git a/test/hbConfig/config.json b/test/hbConfig/config.json new file mode 100644 index 0000000..29738dd --- /dev/null +++ b/test/hbConfig/config.json @@ -0,0 +1,37 @@ +{ + "bridge": { + "name": "Heisenberg", + "username": "AA:BB:CC:DD:EE:01", + "port": 51826, + "pin": "031-45-154" + }, + "description": "HomeBridge HTTP Status Control", + "plugins": [ + "homebridge-yamaha-zone-tv", + "homebridge-config-ui-x" + ], + "platforms": [ + { + "name": "Config", + "port": 8581, + "auth": "none", + "theme": "auto", + "tempUnits": "c", + "lang": "auto", + "sudo": false, + "platform": "config", + "debug": false + }, + { + "platform": "yamaha-zone-tv", + "discovery_timeout": 5, + "radio_presets": true, + "preset_num": true, + "max_volume": 10, + "manual_addresses": { + "Manual": "192.168.1.50" + } + } + ], + "accessories": [] +} \ No newline at end of file