├── .gitignore ├── LICENSE ├── Readme.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .git-ignore 2 | npm-debug.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 robertvorthman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # NO LONGER MAINTAINED 2 | I've moved on to Home Assistant and it's built in Homekit functionality. 3 | See this link for how to recreate the functionality of this Homebridge plugin with Home Assistant. 4 | https://www.home-assistant.io/components/light.template/#theater-volume-control 5 | 6 | # homebridge-marantz-volume 7 | Marantz Receiver plugin for homebridge: https://github.com/nfarina/homebridge 8 | 9 | This plugin allows you to control your Denon or Marantz receiver volume with Siri, with commands like "set the stereo volume to 25%". Your receiver will appear as a light bulb in HomeKit, this is so the brightness characteristic of a light bulb can be leveraged as a way to set the receiver volume by using Siri. 10 | 11 | Unlike other light bulb HomeKit accessories, this plugin ignores power state commands (on/off) by default, this is to avoid having your receiver turn off if you tell Siri to "turn off all the lights". If you want to control the power state of the receiver rather than ignoring it, set the `"controlPower":true` property in the configuration. 12 | 13 | This plugin also allows you to register the "main zone" and "zone 2" of your receiver as independent accessories within HomeKit, if your receiver is multi-zone. 14 | 15 | ## Siri 16 | 17 | Try these Siri commands 18 | 19 | * Set the stereo volume to 25% 20 | * Set the living room to 25% 21 | * Increase/Decrease the stereo volume by 5% 22 | 23 | If those Siri commands do not work, try saying "stereo volume brightness", for example "set the stereo volume brightness to 25%" 24 | 25 | 26 | ![Adjust Stereo Volume Using Siri](https://cloud.githubusercontent.com/assets/4665046/16897532/158d983c-4b82-11e6-984c-11d74e00f46e.gif) 27 | 28 | ## watchOS 3 Home App 29 | Use the Digital Crown to adjust volume with Apple's Home app 30 | 31 | ![Adjust Stereo Volume Using Apple Watch Crown](https://cloud.githubusercontent.com/assets/4665046/16897807/3909c1ba-4b8b-11e6-81d6-f38dbd2aa46c.gif) 32 | 33 | ## iOS 10 Control Center 34 | iOS 10 adds HomeKit shortcuts to the iOS Control Center, so you can adjust the volume without even unlocking your phone. 35 | 36 | ![Adjust Stereo Volume Using Control Center](https://cloud.githubusercontent.com/assets/4665046/16897533/1590c1c4-4b82-11e6-8779-322ad15c31ff.gif) 37 | 38 | # Installation 39 | 40 | 1. Install homebridge: npm install -g homebridge 41 | 2. Install this plugin globally: npm install -g homebridge-marantz-volume 42 | 3. Update your homebridge config file. Example below: 43 | 44 | # Configuration 45 | 46 | Add as an accessory by editing the homebridge config.json file. 47 | 48 | ## Simple Example 49 | 50 | ``` 51 | "accessories": [ 52 | { 53 | "accessory": "marantz-volume", 54 | "name": "Stereo Volume", 55 | "host": "192.168.1.15" 56 | } 57 | ] 58 | ``` 59 | ### 60 | 61 | Newer Denon receivers may need to add port 8080 to the host name, example: 192.168.1.15:8080 62 | 63 | ## Multiple Zones Example 64 | 65 | If your receiver supports a 2nd zone, add 66 | the plugin a second time with `"zone":2` in the accessory properties, the same host, and a different name. 67 | 68 | Configuration sample: 69 | 70 | ``` 71 | "accessories": [ 72 | { 73 | "accessory": "marantz-volume", 74 | "name": "Stereo Volume", 75 | "host": "192.168.1.15", 76 | "maxVolume": 50 77 | }, 78 | { 79 | "accessory": "marantz-volume", 80 | "name": "Outside Volume", 81 | "host": "192.168.1.15", 82 | "maxVolume": 80, 83 | "zone": 2, 84 | "controlPower": true 85 | }, 86 | ... 87 | ] 88 | 89 | ``` 90 | In the above example, the receiver has two zones, the volume control works for both zones (named "Stereo Volume" and "Outside Volume"), 91 | and the power control works is ignored for the main zone and is enabled for the second zone. 92 | 93 | ## Additional Configuration Details 94 | 95 | For newer model Denon's, you might have to add port 8080 to the host option, example: 96 | ``` 97 | "accessories": [ 98 | { 99 | "accessory": "marantz-volume", 100 | "name": "Stereo Volume", 101 | "host": "192.168.1.15:8080" 102 | } 103 | ] 104 | ``` 105 | 106 | The option `maxVolume` defaults to 70 unless otherwise specified as a values between 0 and 100. 107 | 108 | Setting `"mapMaxVolumeTo100":true` will remap the volume percentages that appear in the Home app so that the configured maxVolume will appear as 100% in the Home app. For example, if the maxVolume is 70%, then setting the stereo volume brightness to 50% would set the receiver's volume to 35%. Adjusting the stereo volume knob to 70 will appear as 100% brightness in the Home app. This option could confuse some users to it defaults to off `false`, but it does give the user finer volume control especially when sliding the brightness slider up and down in the Home app. 109 | 110 | The `"controlMute":true` option will change the on/off switch behavior to control the receiver's mute status. If `"controlPower":true` is set, this option will be ignored. 111 | 112 | # Special Thanks 113 | This plugin was built upon code from the following homebridge plugins 114 | 115 | https://www.npmjs.com/package/homebridge-fakebulb by schemish 116 | 117 | https://www.npmjs.com/package/homebridge-denon by stfnhmplr 118 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var parseString = require('xml2js').parseString; 3 | 4 | var Service, Characteristic; 5 | 6 | module.exports = function(homebridge) { 7 | Service = homebridge.hap.Service; 8 | Characteristic = homebridge.hap.Characteristic; 9 | homebridge.registerAccessory("homebridge-marantz-volume", "marantz-volume", ReceiverVolume); 10 | } 11 | 12 | function ReceiverVolume(log, config) { 13 | this.log = log; 14 | 15 | this.name = config['name'] || "Receiver Volume"; 16 | this.maxVolume = config['maxVolume'] || 70; 17 | this.host = config['host']; 18 | this.zone = (config['zone'] || 1) | 0; // default to 1, and make sure its an integer 19 | this.controlPower = !!config['controlPower']; // default to false, and make sure its a bool 20 | this.useFan = !!config['useFan']; // default to false, and make sure its a bool 21 | this.controlMute = !!config['controlMute'] && this.controlPower === false; 22 | this.mapMaxVolumeTo100 = !!config['mapMaxVolumeTo100']; 23 | 24 | //cap maxVolume. Denon/Marantz percentage maxes at 98 in receiver settings 25 | if(this.maxVolume > 98) 26 | this.maxVolume = 98; 27 | 28 | if (!this.host) { 29 | this.log.warn('Config is missing host/IP of receiver'); 30 | callback(new Error('No host/IP defined.')); 31 | return; 32 | } 33 | 34 | if (this.zone < 1 && this.zone > 2) { 35 | this.log.warn('Zone number is not recognized (must be 1 or 2); assuming zone 1'); 36 | this.zone = 1; 37 | } 38 | 39 | this.zoneName = this.zone === 1 ? "MainZone" : "Zone2"; 40 | 41 | if (!this.controlPower) { 42 | this.fakePowerState = 1; //default to on so that brightness will update in HomeKit apps 43 | } 44 | } 45 | 46 | ReceiverVolume.prototype.getStatus = function(callback) { 47 | var statusUrl = `http://${this.host}/goform/form${this.zoneName}_${this.zoneName}XmlStatusLite.xml`; 48 | request.get(statusUrl, function (error, response, body) { 49 | var xml = ''; 50 | if (!error && response.statusCode == 200) { 51 | parseString(xml + body, function (err, result) { 52 | callback(result.item); 53 | }.bind(this)); 54 | }else{ 55 | callback(null); 56 | } 57 | }.bind(this)); 58 | } 59 | 60 | ReceiverVolume.prototype.setControl = function (control, command, callback) { 61 | var controlUrl = `http://${this.host}/goform/formiPhoneApp${control}.xml?${this.zone}+${command}`; 62 | request.get(controlUrl, function (error, response, body) { 63 | if (!error && response.statusCode == 200) { 64 | callback(null); 65 | } else { 66 | callback(error); 67 | } 68 | }.bind(this)); 69 | } 70 | 71 | ReceiverVolume.prototype.getPowerOn = function(callback) { 72 | if (this.controlPower) { 73 | this.getStatus(function(status) { 74 | var powerState = status ? (status.Power[0].value[0] === "ON" ? 1 : 0) : 0; 75 | this.log("Receiver %s Volume power state is %s", this.zoneName, powerState); 76 | callback(null, powerState); 77 | }.bind(this)); 78 | } else if (this.controlMute) { 79 | this.getStatus(function(status) { 80 | var powerState = status ? (status.Mute[0].value[0] === "on" ? 0 : 1) : 0; 81 | this.log("Receiver %s Volume state is %s", this.zoneName, powerState); 82 | callback(null, powerState); 83 | }.bind(this)); 84 | } else { 85 | this.log("Receiver %s Volume power state is %s", this.zoneName, this.fakePowerState); 86 | callback(null, this.fakePowerState); 87 | } 88 | } 89 | 90 | ReceiverVolume.prototype.setPowerOn = function(powerOn, callback) { 91 | if (this.controlPower) { 92 | var command = powerOn ? 'PowerOn' : 'PowerStandby'; 93 | this.log("Set receiver %s volume power state to %s", this.zoneName, command); 94 | this.setControl('Power', command, callback); 95 | } else if (this.controlMute) { 96 | var command = powerOn ? 'MuteOff' : 'MuteOn'; 97 | this.log("Set receiver %s volume state to %s", this.zoneName, command); 98 | this.setControl('Mute', command, callback); 99 | } else { 100 | this.fakePowerState = powerOn ? 1 : 0; 101 | //this.fakePowerState = 1; 102 | this.log("Set receiver %s volume power state to %s", this.zoneName, this.fakePowerState); 103 | callback(null); 104 | } 105 | } 106 | 107 | ReceiverVolume.prototype.setBrightness = function(newLevel, callback) { 108 | 109 | if(this.mapMaxVolumeTo100){ 110 | var volumeMultiplier = this.maxVolume/100; 111 | var newVolume = volumeMultiplier * newLevel; 112 | }else{ 113 | //cap to max volume set in homebridge config.json 114 | var newVolume = Math.min(newLevel, this.maxVolume); 115 | } 116 | 117 | //cap newVolume. //Denon/Marantz percentage maxes at 98 in receiver settings 118 | if(newVolume > 98){ 119 | newVolume = 98; 120 | } 121 | 122 | //convert volume percentage to relative volume 123 | var relativeVolume = (2 * (newVolume - 80)).toFixed(0) / 2.0; 124 | 125 | //cap between -80 and 0 126 | relativeVolume = Math.max(-80.0, Math.min(0.0, relativeVolume)); 127 | 128 | this.setControl('Volume', relativeVolume, callback); 129 | } 130 | 131 | ReceiverVolume.prototype.getBrightness = function(callback) { 132 | this.getStatus(function(status) { 133 | 134 | if(status){ 135 | var volume = parseInt(status.MasterVolume[0].value[0]) + 80; 136 | this.log("Get receiver volume %s ", volume); 137 | 138 | if(this.mapMaxVolumeTo100){ 139 | volume = volume * (100/this.maxVolume); 140 | } 141 | 142 | 143 | callback(null, volume); 144 | }else{ 145 | this.log("Unable to get receiver status"); 146 | callback(null); 147 | } 148 | 149 | }.bind(this)); 150 | } 151 | 152 | ReceiverVolume.prototype.getServices = function() { 153 | if (this.useFan) { 154 | var lightbulbService = new Service.Fan(this.name); 155 | } 156 | else { 157 | var lightbulbService = new Service.Lightbulb(this.name); 158 | } 159 | lightbulbService 160 | .getCharacteristic(Characteristic.On) 161 | .on('get', this.getPowerOn.bind(this)) 162 | .on('set', this.setPowerOn.bind(this)); 163 | if (this.useFan) { 164 | lightbulbService 165 | .addCharacteristic(new Characteristic.RotationSpeed()) 166 | .on('get', this.getBrightness.bind(this)) 167 | .on('set', this.setBrightness.bind(this)); 168 | } 169 | else { 170 | lightbulbService 171 | .addCharacteristic(new Characteristic.Brightness()) 172 | .on('get', this.getBrightness.bind(this)) 173 | .on('set', this.setBrightness.bind(this)); 174 | } 175 | return [lightbulbService]; 176 | } 177 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "homebridge-marantz-volume", 3 | "version": "1.6.3", 4 | "description": "Homebridge plugin to control Denon or Marantz receiver volume with Siri commands", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/robertvorthman/homebridge-marantz-volume.git" 9 | }, 10 | "keywords": [ 11 | "homebridge", 12 | "homebridge-plugin", 13 | "volume", 14 | "marantz", 15 | "denon", 16 | "siri" 17 | ], 18 | "engines": { 19 | "node": ">=0.12.0", 20 | "homebridge": ">=0.2.0" 21 | }, 22 | "dependencies": { 23 | "request": "^2.69.0", 24 | "xml2js": "0.4.x" 25 | }, 26 | "author": "Robert Vorthman", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/robertvorthman/homebridge-marantz-volume/issues" 30 | }, 31 | "homepage": "https://github.com/robertvorthman/homebridge-marantz-volume#readme" 32 | } 33 | --------------------------------------------------------------------------------