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

Big update #84

Open
mkz212 opened this issue May 6, 2023 · 41 comments
Open

Big update #84

mkz212 opened this issue May 6, 2023 · 41 comments

Comments

@mkz212
Copy link

mkz212 commented May 6, 2023

If You want new functions:

  • new types: Blind, Motion, Lock, Garage Door, Contact, Security (4 values switch), Thermostat
  • option to set sensor value on startup: on, off, set value (for dimmer or blind) or last used (cache)
  • option to chose timer unit: days, hour, minutes, seconds, miliseconds
  • new settings display, with sections and with showing and hiding fields depending on the need
  • more info in logs
  • small fixes

replace config.schema.json to:

{
	"pluginAlias": "DummySwitch",
    "pluginType": "accessory",
    "singular": false,
    "schema": {
	    "type": "object",
        "properties": {
            "name": {
                "title": "Name",
				"description": "Select name of the sensor.",
                "type": "string",
                "required": true
            },
            "type": {
                "title": "Type",
                "description": "Select type of the sensor.",
                "type": "string",
                "default": "switch",
                "required": true,
                "oneOf": [
                  { "title": "Switch", "enum": ["switch"] },
                  { "title": "Dimmer", "enum": ["dimmer"] },
                  { "title": "Blind", "enum": ["blind"] },
				  { "title": "Motion", "enum": ["motion"] },
				  { "title": "Lock", "enum": ["lock"] },
				  { "title": "Contact", "enum": ["contact"] },
				  { "title": "Security", "enum": ["security"] },
				  { "title": "Thermostat", "enum": ["thermostat"] }
                ]
            },
			"startup": {
                "title": "After startup",
                "description": "Select sensor state after startup.",
                "type": "string",
                "default": "off",
                "required": true,
                "oneOf": [
                  { "title": "Set Off", "enum": ["off"] },
                  { "title": "Set On", "enum": ["on"] },
                  { "title": "Set Value", "enum": ["setValue"] },
				  { "title": "Last used value", "enum": ["last"] }
                ]
            },		
            "startupValue": {
                "title": "Value",
                "type": "integer", 
				"default": 0,
                "maximum": 100,
                "description": "Override starting value. 0 = disabled.",
	            "condition": {
	              "functionBody": "return ((model.type === 'dimmer' || model.type === 'blind') && (model.startup === 'setValue'));"
	            }
            },
            "timerEnabled": {
                "title": "Enable timer",
                "type": "boolean",
                "default": true,
                "description": "Disable timer if sensor should remain it's state."
            },
            "resettable": {
                "title": "Resettable",
                "type": "boolean",
                "default": false,
                "description": "Reset timer on each activity.",
	            "condition": {
	              "functionBody": "return model.timerEnabled === true;"
	            }
            },
            "time": {
                "title": "Time",
                "type": "number",
                "default": 1,
                "description": "Sensor will change state after this time.",
	            "condition": {
	              "functionBody": "return model.timerEnabled === true;"
	            }
            },
            "timeUnit": {
                "title": "Time Unit",
                "description": "",
                "type": "string",
                "default": "seconds",
                "required": true,
                "oneOf": [
                  { "title": "Miliseconds", "enum": ["miliseconds"] },
                  { "title": "Seconds", "enum": ["seconds"] },
                  { "title": "Minutes", "enum": ["minutes"] },
				  { "title": "Hours", "enum": ["hours"] },
				  { "title": "Days", "enum": ["days"] }
                ],
	            "condition": {
	              "functionBody": "return model.timerEnabled === true;"
	            }
            },
            "random": {
                "title": "Random",
                "type": "boolean",
                "default": false,
                "description": "Randomize the time.",
	            "condition": {
	              "functionBody": "return model.timerEnabled === true;"
	            }
            },
            "reverse": {
                "title": "Reverse",
                "type": "boolean",
                "default": false,
                "description": "Reverse sensor operation.",
	            "condition": {
	              "functionBody": "return model.timerEnabled === true;"
	            }
            },
            "disableLogging": {
                "title": "DisableLogging",
                "type": "boolean",
                "default": false,
                "description": "No state change information (On/Off) will be logged."
            }

        }
    },
    "layout": [		
		{
			"type": "fieldset",
			"title": "General",
			"description": "",
			"expandable": false,
			"expanded": true,
			"items": [ 
				{
					"type": "flex",
					"flex-flow": "row wrap",
					"items": ["name", "type"]
				}
  
			]
		},
	    {
			"type": "fieldset",
			"title": "After start",
			"description": "",
			"expandable": false,
			"expanded": true,
			"items": [	
				{
					"type": "flex",
					"flex-flow": "row wrap",
					"items": ["startup", "startupValue"]
				}	  
				
			]
		},
	    {
			"type": "fieldset",
			"title": "Timer",
			"description": "",
			"expandable": false,
			"expanded": true,
			"items": [		  
				{
					"type": "flex",
					"flex-flow": "row wrap",
					"items": ["timerEnabled", "resettable"]
				},

				{
					"type": "flex",
					"flex-flow": "row wrap",
					"items": ["time", "timeUnit"]
				},

				{
					"type": "flex",
					"flex-flow": "row wrap",
					"items": ["random", "reverse"]
				}	  
			]
		}, 
		{
			"type": "fieldset",
			"title": "Logs",
			"description": "",
			"expandable": false,
			"expanded": true,
			"items": [
				{
					"type": "flex",
					"flex-flow": "row wrap",
					"items": ["disableLogging", ""]
				}
			]
		}
	]
}




and replace index.js to:


"use strict";

var Service, Characteristic, HomebridgeAPI;
const { HomebridgeDummyVersion } = require('./package.json');

module.exports = function(homebridge) {
	Service = homebridge.hap.Service;
	Characteristic = homebridge.hap.Characteristic;
	HomebridgeAPI = homebridge;
	homebridge.registerAccessory("homebridge-dummy", "DummySwitch", DummySwitch);
}


function DummySwitch(log, config) {
	this.log = log;
	this.name = config.name;
	this.type = config.type;
	this.startup = config.startup;
	this.startupValue = config.startupValue ? config.startupValue : false;
	this.timerEnabled= config.timerEnabled;	
	this.reverse = config.reverse;
	this.time = config.time ? config.time : 1000;		
	this.timeUnit = config.timeUnit;	
	this.resettable = config.resettable;
	this.timer = null;
	this.random = config.random;
	this.disableLogging = config.disableLogging;
	
	
	if (this.type == 'switch') {
		this._service = new Service.Switch(this.name);
		this.modelString = "Dummy Switch";
	}
	else if (this.type == 'dimmer') {
		this._service = new Service.Lightbulb(this.name);
		this.modelString = "Dummy Dimmer";
	} 
	else if (this.type == 'blind') {
		this._service = new Service.WindowCovering(this.name);
		this.modelString = "Dummy Blind";
	} 
	else if (this.type == 'motion') {
		this._service = new Service.MotionSensor(this.name);
		this.modelString = "Dummy Motion";
	} 
	else if (this.type == 'lock') {
		this._service = new Service.LockMechanism(this.name);
		this.modelString = "Dummy Lock";
	} 
	else if (this.type == 'garage') {
		this._service = new Service.GarageDoorOpener(this.name);
		this.modelString = "Dummy Garage";
	} 
	else if (this.type == 'contact') {
		this._service = new Service.ContactSensor(this.name);
		this.modelString = "Dummy Contact";
	} 
	else if (this.type == 'security') {
		this._service = new Service.SecuritySystem(this.name);
		this.modelString = "Dummy Security";
	} 
	else if (this.type == 'thermostat') {
		this._service = new Service.Thermostat(this.name);
		this.modelString = "Dummy Thermostat";
	} 
	

	this.informationService = new Service.AccessoryInformation();
	this.informationService
		.setCharacteristic(Characteristic.Manufacturer, 'Homebridge')
		.setCharacteristic(Characteristic.Model, this.modelString)
		.setCharacteristic(Characteristic.FirmwareRevision, HomebridgeDummyVersion)
		.setCharacteristic(Characteristic.SerialNumber, 'Dummy-' + this.name.replace(/\s/g, '-'));

	this.cacheDirectory = HomebridgeAPI.user.persistPath();
	this.storage = require('node-persist');
	this.storage.initSync({dir:this.cacheDirectory, forgiveParseErrors: true});




	if (this.type == 'switch') {
		this._service.getCharacteristic(Characteristic.On)
		.on('set', this._setValue.bind(this));
	}
	else if (this.type == 'dimmer') {
		this._service.getCharacteristic(Characteristic.On)
			.on('set', this._setValue.bind(this));
		
		this._service.getCharacteristic(Characteristic.Brightness)
			.on('set', this._setValue.bind(this));		
	}
	else if (this.type == 'blind') {
		this._service.getCharacteristic(Characteristic.TargetPosition)
	        .on('set', this._setValue.bind(this));
	}
	else if (this.type == 'motion') {
		this._service.getCharacteristic(Characteristic.MotionDetected)
	        .on('set', this._setValue.bind(this));
	}
	else if (this.type == 'lock') {
		this._service.getCharacteristic(Characteristic.LockTargetState)
	        .on('set', this._setValue.bind(this));
	}
	else if (this.type == 'garage') {
		this._service.getCharacteristic(Characteristic.TargetDoorState)
	        .on('set', this._setValue.bind(this));
	}
	else if (this.type == 'contact') {
		this._service.getCharacteristic(Characteristic.ContactSensorState)
	        .on('set', this._setValue.bind(this));
	}
	else if (this.type == 'security') {
		this._service.getCharacteristic(Characteristic.SecuritySystemTargetState)
	        .on('set', this._setValue.bind(this));
	}
	else if (this.type == 'thermostat') {
		this._service.getCharacteristic(Characteristic.TargetHeatingCoolingState)
	        .on('set', this._setValue.bind(this));
			
		this._service.getCharacteristic(Characteristic.TargetTemperature)
	        .on('set', this._setValue.bind(this));
	}
	

  
	if (this.startup == 'on') {
	
	    if (this.type == 'switch') {
			this._service.setCharacteristic(Characteristic.On, true);
		}
		else if (this.type == 'dimmer') {		
			this._service.setCharacteristic(Characteristic.On, true); 
			this._service.setCharacteristic(Characteristic.Brightness, 100);
		}		
		else if (this.type == 'blind') {
			this._service.setCharacteristic(Characteristic.TargetPosition, 100);
		}
		else if (this.type == 'motion') {
			this._service.setCharacteristic(Characteristic.MotionDetected, 1);
		}
		else if (this.type == 'lock') {
			this._service.setCharacteristic(Characteristic.LockTargetState, 0);
		}
		else if (this.type == 'garage') {
			this._service.setCharacteristic(Characteristic.TargetDoorState, 0);
		}
		else if (this.type == 'contact') {
			this._service.setCharacteristic(Characteristic.ContactSensorState, 'CONTACT_NOT_DETECTED');
		}
		else if (this.type == 'security') {
			this._service.setCharacteristic(Characteristic.SecuritySystemTargetState, 0);	
		}
		else if (this.type == 'thermostat') {
			this._service.setCharacteristic(Characteristic.TargetHeatingCoolingState, 3);
		}
		
	}
	
	else if (this.startup == 'setValue' && this.startupValue && (this.type == 'dimmer' || this.type == 'blind')) {
		
		if (this.type == 'dimmer') {
			this._service.setCharacteristic(Characteristic.On, true);
			this._service.setCharacteristic(Characteristic.Brightness, this.startupValue);
		}
		else if (this.type == 'blind') {
			this._service.setCharacteristic(Characteristic.TargetPosition, this.startupValue);
		}	
	}  
  
	else if (this.startup == 'last') {
	  
		if (this.type == 'switch') {
			var cachedState = this.storage.getItemSync(this.name + 'on');
			if((cachedState === undefined) || (cachedState === false)) {
				this._service.setCharacteristic(Characteristic.On, false);
			} 
			else {
				this._service.setCharacteristic(Characteristic.On, true);
			}
		}
  	
		else if (this.type == 'dimmer') {
			var cachedValue = this.storage.getItemSync(this.name + 'on');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.On, false);
			} 
			else {				
				this._service.setCharacteristic(Characteristic.On, true);			
			}

			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.Brightness, 0);
			} 
			else {				
				this._service.setCharacteristic(Characteristic.Brightness, cachedValue);			
			}

		}
  
	  	else if (this.type == 'blind') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.TargerPosition, 0);
			} 
			else {
				this._service.setCharacteristic(Characteristic.TargetPosition, cachedValue);
			}
	  	}
		
	  	else if (this.type == 'motion') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.MotionDetected, 0);
			} 
			else {
				this._service.setCharacteristic(Characteristic.MotionDetected, cachedValue);
			}
	  	}
		
	  	else if (this.type == 'lock') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.LockTargetState, 1);
			} 
			else {
				this._service.setCharacteristic(Characteristic.LockTargetState, cachedValue);
			}
	  	}
		
	  	else if (this.type == 'garage') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.TargetDoorState, 1);
			} 
			else {
				this._service.setCharacteristic(Characteristic.TargetDoorState, cachedValue);
			}
	  	}
		
	  	else if (this.type == 'contact') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.ContactSensorState, 'CONTACT_DETECTED');
			} 
			else {
				this._service.setCharacteristic(Characteristic.ContactSensorState, cachedValue);
			}
	  	}
		
	  	else if (this.type == 'security') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.SecuritySystemTargetState, 0);
			} 
			else {
				this._service.setCharacteristic(Characteristic.SecuritySystemTargetState, cachedValue);
			}
	  	}
		
	  	else if (this.type == 'thermostat') {
			var cachedValue = this.storage.getItemSync(this.name + 'value');
			if ((cachedValue == undefined) || cachedValue == 0) {				
				this._service.setCharacteristic(Characteristic.TargetHeatingCoolingState, 0);
			} 
			else {
				this._service.setCharacteristic(Characteristic.TargetHeatingCoolingState, cachedValue);
			}

	  	}

	}
	
	else {
	
		if (this.type == 'switch') {	    
			this._service.setCharacteristic(Characteristic.On, false);
		}		
		else if (this.type == 'motion') {
			this._service.setCharacteristic(Characteristic.MotionDetected, 0);
		}
		else if (this.type == 'lock') {
			this._service.setCharacteristic(Characteristic.LockTargetState, 1);
		}
		else if (this.type == 'garage') {
			this._service.setCharacteristic(Characteristic.TargetDoorState, 1);
		}
		else if (this.type == 'contact') {		
			this._service.setCharacteristic(Characteristic.ContactSensorState, 'CONTACT_DETECTED');
		}
		else if (this.type == 'security') {
			this._service.setCharacteristic(Characteristic.SecuritySystemTargetState, 3);	
		}
		else if (this.type == 'thermostat') {
			this._service.setCharacteristic(Characteristic.TargetHeatingCoolingState, 0);
		}
		else if (this.type == 'dimmer') {		
			this._service.setCharacteristic(Characteristic.On, false); 
			this._service.setCharacteristic(Characteristic.Brightness, 0);
		}
		else if (this.type == 'blind') {
			this._service.setCharacteristic(Characteristic.TargetPosition, 0);
		}
			
	}
	
	
  	if ((this.type == 'thermostat') && (this.storage.getItemSync(this.name + 'value2') != undefined)) {
						
			this._service.setCharacteristic(Characteristic.TargetTemperature, cachedValue);

  	}

}



DummySwitch.prototype.getServices = function() {
	return [this.informationService, this._service];
}

function randomize(time) {
	return Math.floor(Math.random() * (time + 1));
}





DummySwitch.prototype._setValue = function(value, callback) {


	if (!this.disableLogging) {
		
		if (value === true) {
			this.log("ON");
		}

		else if (value === false) {
			this.log("OFF");
		}

		else if ((this.type == 'lock') && (value == 1)) {
			this.log("Lock");
		}

		else if ((this.type == 'lock') && (value == 0)) {
			this.log("Unlock");
		}

		else if ((this.type == 'garage') && (value == 1)) {
			this.log("Open");
		}

		else if ((this.type == 'garage') && (value == 0)) {
			this.log("Close");
		}

		else if ((this.type == 'motion') && (value == 0)) {
			this.log("Motion not detected");
		}

		else if ((this.type == 'motion') && (value == 1)) {
			this.log("Motion detected");
		}

		else if ((this.type == 'contact') && (value == 'CONTACT_DETECTED')) {
			this.log("Contact detected");
		}

		else if ((this.type == 'contact') && (value == 'CONTACT_NOT_DETECTED')) {
			this.log("Contact not detected");
		}

		else if ((this.type == 'security') && (value == 0)) {
			this.log("Stay Arm");
		}

		else if ((this.type == 'security') && (value == 1)) {
			this.log("Away Arm");
		}

		else if ((this.type == 'security') && (value == 2)) {
			this.log("Night Arm");
		}

		else if ((this.type == 'security') && (value == 3)) {
			this.log("Disarm");
		}

		else if ((this.type == 'thermostat') && (value == 0)) {
			this.log("OFF");
		}

		else if ((this.type == 'thermostat') && (value == 1)) {
			this.log("Heat");
		}

		else if ((this.type == 'thermostat') && (value == 2)) {
			this.log("Cool");
		}

		else if ((this.type == 'thermostat') && (value == 3)) {
			this.log("Auto");
		}

		else {
			this.log(value);
		}

	}


	

	
	// Calculate Timer
  
	var delay = this.time;

	if (this.timeUnit == 'seconds') {
		delay = this.time * 1000;
	}
	else if (this.timeUnit == 'minutes') {
		delay = this.time * 60000;
	}
	else if (this.timeUnit == 'hours') {
		delay = this.time * 3600000;
	}
	else if (this.timeUnit == 'days') {
		delay = this.time * 86400000;
	}
	
	
	
	// Randomize Delay
	
	if (this.random) {
		delay = randomize(delay);
	} 
	
	
  
  
	// Clear Timer
  
	if (this.resettable) {
		clearTimeout(this.timer);

		if (!this.disableLogging) {
			this.log("Reset Timer");
		}
		
	}
	
	

	
	// Target to Curent value
	
	if (this.type == 'blind') {
		this._service.setCharacteristic(Characteristic.CurrentPosition, value);
	}

	else if (this.type == 'lock') {
		this._service.setCharacteristic(Characteristic.LockCurrentState, value);
	}
	
	else if (this.type == 'garage') {
		this._service.setCharacteristic(Characteristic.CurrentDoorState, value);
	}
	
	else if (this.type == 'security') {
		this._service.setCharacteristic(Characteristic.SecuritySystemCurrentState, value);
	}
	
	else if (this.type == 'thermostat') {
		
		if (value == 0 || value == 1 || value == 2) { 
			this._service.setCharacteristic(Characteristic.CurrentHeatingCoolingState, value);
		}
		else if (value == 3) {
			this._service.setCharacteristic(Characteristic.CurrentHeatingCoolingState, 1);
		}
		else {
			this._service.setCharacteristic(Characteristic.CurrentTemperature, value);
		}
		
	}
	
	
	

	
	
	// Set Timer
	if (this.timerEnabled) {	


		if (!this.reverse) {

			if ((this.type == 'switch') && (value === true)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.On, false);
				}.bind(this), delay);
			}
			else if ((this.type == 'dimmer') && (value === true)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.On, false);
				}.bind(this), delay);
			}
			else if ((this.type == 'dimmer') && (value != 0)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.Brightness, 0);
				}.bind(this), delay);
			}
			else if ((this.type == 'blind') && (value != 0)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.TargetPosition, 0);
				}.bind(this), delay);
			}
			else if ((this.type == 'motion') && (value == 1))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.MotionDetected, 0);
				}.bind(this), delay);
			}
			else if ((this.type == 'lock') && (value == 0))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.LockTargetState, 1);
				}.bind(this), delay);
			}
			else if ((this.type == 'garage') && (value == 0))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.TargetDoorState, 1);
				}.bind(this), delay);
			}
			else if ((this.type == 'contact') && (value == 'CONTACT_NOT_DETECTED'))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.ContactSensorState, 'CONTACT_DETECTED');
				}.bind(this), delay);
			}
			else if ((this.type == 'security') && (value != 3))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.SecuritySystemTargetState, 3);
				}.bind(this), delay);
			}
			else if ((this.type == 'thermostat') && (value != 0))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.TargetHeatingCoolingState, 0);
				}.bind(this), delay);
			}
		}
		
		else if (this.reverse) {
		
			if ((this.type == 'switch') && (value === false)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.On, true);
				}.bind(this), delay);
			}
			else if ((this.type == 'dimmer') && (value === false)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.On, true);
				}.bind(this), delay);
			}
			else if ((this.type == 'dimmer') && (value != 100)) {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.Brightness, 100);
				}.bind(this), delay);
			}
			else if ((this.type == 'blind') && (value != 100))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.TargetPosition, 100);
				}.bind(this), delay);
			}
			else if ((this.type == 'motion') && (value == 0))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.MotionDetected, 1);
				}.bind(this), delay);
			}
			else if ((this.type == 'lock') && (value == 1))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.LockTargetState, 0);
				}.bind(this), delay);
			}
			else if ((this.type == 'garage') && (value == 1))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.TargetDoorState, 0);
				}.bind(this), delay);
			}
			else if ((this.type == 'contact') && (value == 'CONTACT_DETECTED'))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.ContactSensorState, 'CONTACT_NOT_DETECTED');
				}.bind(this), delay);
			}
			else if ((this.type == 'security') && (value == 3))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.SecuritySystemTargetState, 0);
				}.bind(this), delay);
			}
			else if ((this.type == 'thermostat') && (value == 0))  {
				this.timer = setTimeout(function() {
				this._service.setCharacteristic(Characteristic.TargetHeatingCoolingState, 3);
				}.bind(this), delay);
			}
		}


		if ((!this.disableLogging) && (this.timer)) {
			if (!this.random){
				this.log("Set Timer: " + this.time + " " + this.timeUnit );
			}
			else {
				this.log("Setting random Timer: " + delay + " ms");
			}
		}

	}

	
	
		
	if (value === true || value === false) {

		this.storage.setItemSync(this.name + 'on', value);
		
	}

	else if ((this.type == 'thermostat') && (value > 3)) {

		this.storage.setItemSync(this.name + 'value2', value);

	}

	else {

		this.storage.setItemSync(this.name + 'value', value);

	}
		
	

	callback();
}

@nfarina what do you think? This is my suggestion for the next update, to 1.0.0.

@dadsalleb
Copy link

I would love to use the dummy sensor. Not sure this patch will be merged into the master repo..

@mkz212
Copy link
Author

mkz212 commented Jun 7, 2023

It depends on the author of the plugin. I have great hope for that.

@nfarina
Copy link
Owner

nfarina commented Jun 8, 2023

Hello, absentee landlord here :) sorry I'm slow to respond, I don't use this plugin myself anymore. This is a lot of stuff! What is the purpose of making specific dummy accessories like window blinds, etc?

@mkz212
Copy link
Author

mkz212 commented Jun 8, 2023

I collected different conclusions, from different people, from different threads and somehow it came out. But different types are not the only modification. Yes, I think it's a lot of changes but simple to introduce. Just in time for version 1.0. 😀

@mkz212
Copy link
Author

mkz212 commented Jun 9, 2023

Different types have their advantages. For example, in the Apple Home application, you can enable notifications for: Lock, Garage, Security. Motion is displayed in status and not in devices. Thermostat and Security are more extensive devices.

In addition to new devices:

  • timer reset is with every activity: on / off
  • you can choose what the device status should be at homebridge startup: on, off, last set (cache) or set a specific value (dimmer, blind)
  • You can choose whether the timer should be turned on and when it should be activated.
  • no need to convert the timer in milliseconds, you can in seconds, minutes, hours, days
  • there is more information in the homebridge logs
  • Eliminated several warnings that appeared in the homebridge logs.
  • New settings view (in homebridge). With fields that appear and hide as needed.

@nfarina
Copy link
Owner

nfarina commented Jun 9, 2023

Appreciate the writeup! I'm still struggling a bit though - originally the purpose of the dummy switch was to make a mechanism to trigger multiple scenes in HomeKit, kind of a workaround for missing functionality.

But these other fake accessories, what is their practical purpose?

@dadsalleb
Copy link

For the fake sensors, we can get a notification when using the sensor while the standard or dummy switch don't have the option. It is kind of limitation of Apple Home but this can be a good workaround. Not sure about other accessories but @mkz212 may have idea.

@mkz212
Copy link
Author

mkz212 commented Jun 9, 2023

As @sooyoung0321 writes, such types have more opportunities in Apple Home, especially in iOS 17: notifications and logs etc. My code only adds additional options, you still have the option to choose a regular switch. But with such an ordinary switch, you have additional options to choose what state should be at the start, it is reset with each activity, you still have the ability to set the timer, etc.

All these things are not my invention but the collected wishes of the users of this plugin.

You don't lose anything, you can only gain! Please give it a chance! 😀👍

@mkz212
Copy link
Author

mkz212 commented Jun 10, 2023

My examples of automation where your plug-in is useful to me, and even it is necessary:

  • When the motion sensor detects movement, it turns on the Dummy Switch and turns it off after 18 hours. Each movement detection extends the timer. That's why I had to change your code so that the reset was with every activity, not only when turning off. Then this Dummy Switch uses to control the heating - if Dummy is turned off it lowers the set temperature. Here I needed some Dummy Switch to be turned on after restarting homebridge to avoid the situation that it will be too cold.

  • I have a trigger set to control the air conditioning. Every 15 minutes he checks the conditions. I wanted the climate to turn on for a minimum of an hour.

I will not answer you how to use other types of sensors but I know that other users have ideas for it. I know for sure that additional types of sensors are only optional and you do not need to use them. In addition to the sensor types, I added many other things. Code is ready and tested and works well (at least for me).

@incline02
Copy link

incline02 commented Jul 2, 2023

@nfarina @mkz212

I used dummies to give my home memory. I'll try to be concise and illustrate with exemples:

When I turn on the PS5 (plugin), a scene turns the living room lights blue and turns on the dummy plugin "PS5" on. If I go to to another room, that room's sensor will turn off the lights in the living room but the dummy ps5 stays on. When I sit on the sofa, motion is detected: homekit will test if dummy PS5 is on, if yes, then lights turn blue again = My house remembers I'm playing ps5 thanks to the dummy and so PS5 scene is persistent. Notice how I could have resume the scene upon motion sensor but rather when I sit on the sofa thanks to a vibration sensor. It feels much more organic and that's thanks to you.

I also have a "Guest mode" dummy where, if on, homekit stops turning off the lights behind me/in the room I just left or increasing the volume of the HomePod because I left to another room.

I like to start an ambiant sound when I enter my bedroom at 50% but It's too loud when I go to sleep. So I have a vibration sensor in my bed that turns down the volume to 5% when I lay down. But if I'm going to the bathroom (right next to the bedroom) at night and come back into the bedroom, it'd go back to 50% right? So I have a dummy "In bed presence" that prevents going back to 50%. If my partner is already in bed and I trigger motion in the bedroom, that dummy covers for that too and volume stays at 5%

Simpler things: automating things only once a day:

  • in the morning, my coffee morning starts if motion is detected in the living. which turns off the dummy plugin "Morning coffee": It won't start if motion is detected again.
  • I have a robot vacuum which is set to clean at 12pm or if I leave home. You can see how it'd go twice most days, which I don't need. But if dummy "clean daily" is on (mean a cleaning round was already done), it won't go a second time that day and reset at 8am.
  • I have a dummy dimmer that changes % according to how dark it gets outside, which will determine the level of dim to the lights as I go around my home and lights turn off behind me and on where I am, it remembers the level. you literally gave my home a Circadian Rhythm / Apple's adaptive lighting

@nfarina Nick your plugin literally gave my home persistence and memory. It's very powerful (but does require to create complex if-condition-based automation if you want to do fancier things like I do). But if you're not using it, are you using an alternative that provides dummies too?

@mkz212
Copy link
Author

mkz212 commented Jul 2, 2023

@incline02 Thank You for your examples. What do you think about my plugin development proposal? Do you have any suggestions what else to add?

@incline02
Copy link

incline02 commented Jul 2, 2023

Sure, I'm happy to provide feedback

new types: Blind, Motion, Lock, Garage Door, Contact, Security (4 values switch), Thermostat

I join @nfarina is asking the practical purpose: don't all of the above come down to reporting Virtual On/Off statuses or a given %? It is true that they will unlock different views/properties in HomeKit but nothing actionable as they are virtual. I don't have the blinds or Garage door but I have all the others and I'm not sure why I would need them virtual. I can see a a way to use them but it's rather convoluted: say I have homekit capable blind or door or else but it doesn't advertise as such because the manufacture was lazy or whatever and so they show up as smart plug where OFF means blind/door closed. With your adjustments, I could substitute this plug profile to an actual garage door profile and as such via automations (if the dummy blinds Is set to closes, the real plug turns off. Then in the home app, I'd have to hide it away in favour of the dummy) benefits? Improving Siri/natural language: use "open the curtains" instead of "turn on the curtain". But that's about as useful it get; on top of my mind. I would add, if not too hard to maintain, it's better to have more profiles that not enough. And someone like me, will come up with something creative.

option to set sensor value on startup: on, off, set value (for dimmer or blind) or last used (cache)

Persistence through reboot is great. I need this. If I reboot at night, because of the % dimmer, my systems thinks it's day so I set all motion sensors to reset the % correctly. cumbersome. Last used would be great, set value, would be great.

option to chose timer unit: days, hour, minutes, seconds, miliseconds

I would design the homebridge UI so it offers these, but let it pass the data to homebridge in the unit homebridge prefers, to avoid any bug. But I think it's a great one too.

new settings display, with sections and with showing and hiding fields depending on the need
more info in logs
small fixes

that's always welcomed. I actually wish homebridge/or this plug could offer Dummy Management because I have around 20 of them and they could easily be sorted by category

Also as we speak, homebridge-Dummy is rendering my entire homebridge non-responsive randomly til I reboot. I could seriously use an update as I realise my dependancy on @nfarina :D ! I'm a little worried Nick isn't using their own plugin anymore :D !

I'm now reverting back to old versions to find out if it'll fix my issues but any fix is highly welcomed.

@mkz212
Copy link
Author

mkz212 commented Jul 2, 2023

Thank You. My code fix problem with no response. But I'm not the author and only @nfarina can make it public.

@incline02
Copy link

I'm not too familiar with gihub, only use to it open issues or search for fix so pardon my question: can't you create a fork if @nfarina isn't interested in maintenance?

@dadsalleb
Copy link

or you can open a separate repository such as dummy-extension, and you can maintain it on it.

@mkz212
Copy link
Author

mkz212 commented Jul 2, 2023

I still hope @nfarina will use my code and update plugin for all. Unfortunately, I also don't know much about github and I don't know how to make these fork or repository.

@incline02
Copy link

@mkz212 on top of mind, given that it's just a copy paste of a project after which, replacing some files, it can't be complicated !

I found a tutorial that I'm willing to follow but it's your ideas and so you should be the owner of the new copied project. Would you like to give it a try?

https://docs.github.com/en/get-started/quickstart/fork-a-repo

@mkz212
Copy link
Author

mkz212 commented Jul 3, 2023

Maybe let's ask the author for his opinion? @nfarina What do you think? Are you going to use my code to update the plugin? Are you going to develop plugin or have you completely abandoned the project?

@incline02 If the author will be not interested in updating the plugin, you can use my code.

@nfarina
Copy link
Owner

nfarina commented Jul 6, 2023

Sorry for the very late reply. I don't use this plugin anymore and you can tell I haven't updated this repo in some time.

Expanding this scope of this plugin using your code is something I cannot sign up for right now. But I highly encourage you to fork/copy my code and publish your own repository! It's not too difficult and then you can have complete control.

@incline02
Copy link

incline02 commented Jul 6, 2023

solid copy HQ. I'll have a look into it today

@mkz212 the fix for unresponsive device: how did you fix it? fixed it on my own by deleting all cached accessories (assuming I should have deleted only the dummy switches but there was a long list

edit: scratch it, it happened again

@incline02
Copy link

Alright, it's created https://github.com/incline02/homebridge-dummy

and updated with your changes. Only thing is, I can't find a way to "publish it" into homebridge's repo so one can find it and install it via homebridge. I keep looking but, any help?

@nfarina
Copy link
Owner

nfarina commented Jul 6, 2023

Nice! You're welcome to use the homebridge-dummy name of course but you might have more luck picking a new name - that will help folks who are looking for this extended functionality.

To make it installable in Homebridge, you'll need to publish it to npm. Here's their getting started guide.

@incline02
Copy link

thanks for the tip! named changed! I'll publish it today I hope

@incline02
Copy link

Alright, it appears in Homebridge when you search for it. search for "incline_02" to find "homebridge-dummy-incline_02-beta"

Let me know what goes wrong

@incline02
Copy link

HEADS UP
It will use your "old" config from nFarina's original project and show them as "not supported" in homekit.

The fix:

  1. In the homebridge interface, go to plugin
  2. find my plugin
  3. click SETTINGS
  4. for each dummy you'll find in SETTINGS, change its type to another one ex Dimmer, and then back to what you had before

I confirm @mkz212 new types of dummies are in there too

And so far, the bug I reported isn't anymore.

Let's keep this open for some after care. please note I'll be attending a private event til Monday morning. Do come with feedback though!

@bubffm
Copy link

bubffm commented Oct 9, 2023

Appreciate the writeup! I'm still struggling a bit though - originally the purpose of the dummy switch was to make a mechanism to trigger multiple scenes in HomeKit, kind of a workaround for missing functionality.

But these other fake accessories, what is their practical purpose?

Dummy Irrigation would get me the correct icons into Home App for my watering systems which are triggered by switches.

@mkz212
Copy link
Author

mkz212 commented Oct 11, 2023

@nfarina If you want I can make my code as pull request. Would you then accept the changes?

@mkz212 mkz212 mentioned this issue Oct 12, 2023
@mkz212
Copy link
Author

mkz212 commented Oct 12, 2023

@bubffm I can add Irrigation, but I am not the author of the plugin. It all depends on @nfarina . I just added pull request with all these big changes.

@mkz212
Copy link
Author

mkz212 commented Oct 26, 2023

@nfarina I added a pull request with all these changes. But I know that it's a lot of changes for one pull request. Perhaps you prefer me to divide it into single changes?

The question is whether you are still going to develop the plugin? If not, maybe you consider pass it to someone who would like to?

@dadsalleb
Copy link

Meanwhile, I'd like to test this but don't know how to install it from a separate source. I tried to find a way to install a plugin from the source code but no luck. Could you please point me out how to do it?

@mkz212
Copy link
Author

mkz212 commented Oct 26, 2023

I've never done it before, but from what I read, in homebridge terminal type:
npm install mkz212/homebridge-dummy#big-update --save
But I check and for me it doesn't work.

Or connect via FTP and change code in these two files.

@5xPa
Copy link

5xPa commented Oct 27, 2023

I'm interested in this revision. Especially being able to set security notification. I have interfaced parts of my alarm system (Texecomm) to shelly uni's using mongoose firmware. For example when down stairs alarm is set triggers a shelly uni, which then turns all the downstairs lights off.

My question does this install along side the existing dummy switch. Or do I need to uninstall the original install the revision. Then recreate the dummy switches and timers? Which then require me to rebuild the scenes etc

@mkz212
Copy link
Author

mkz212 commented Oct 27, 2023

@5xPa I think that it will override plugin. But I changed the code a bit now so that it should work with the current settings - now only miliseconds can be set, and in my version miliseconds are default and you can change it.

@mkz212
Copy link
Author

mkz212 commented Oct 28, 2023

@5xPa I check this and for me npm install mkz212/homebridge-dummy#big-update --save doesn't work.

@5xPa
Copy link

5xPa commented Oct 28, 2023 via email

@mkz212
Copy link
Author

mkz212 commented Oct 28, 2023

I think you can try. Since then I have only changed the fact that by default the time is set to milliseconds as in the original. But if it installs as an independent plugin, it doesn't matter.

@mkz212
Copy link
Author

mkz212 commented Oct 28, 2023

Ok now it should work: npm install mkz212/homebridge-dummy#big-update --save .

It will override plugin but you can return to the original code at any time: in the Plugins tab, click the key icon next to the plugin, then: install another version.

@dadsalleb
Copy link

I'm not brave enough to update the branch, so I tried to install a separate plugin Incline_02 Beta. But, it looks like the Incline_02 Beta plugin shares the same configuration as this dummy switch plugin. That said, once something is changed in Incline_02 Beta, this dummy plugin is affected. So, I deleted Incline_02 Beta.

@mkz212
Copy link
Author

mkz212 commented Nov 2, 2023

Writing this code, my idea was for the author of the original plugin to include new additions and corrections in his plugin, not to create a new plugin. That's why I added a pull request as well as the code itself and information on which files to replace. Since this is not a separate plugin but corrections to the current one, it is obvious that it will be the same configuration. But in my opinion the code does not take anything but only corrects and adds.

@mkz212
Copy link
Author

mkz212 commented Nov 15, 2023

@nfarina

Maybe you could create a new branch and merge PR to it with this big update and release it as a beta? Who will want will install and test it.

Do you have any comments what to improve?

If you do not want to release the entire code as a beta because it is too big change, if I add a small PRs with small changes, is there a chance that you will include them?

If you are busy, maybe you could consider appointing someone as an administrator? This is a great plugin that a lot of people use and it would be nice if it was further supported and developed.

@dadsalleb
Copy link

dadsalleb commented Nov 15, 2023

@mkz212 It looks like the original author doesn't want to make any change on this plugin or takeover it. We cannot force him/her to do that. I think you'd better make a separate git and plugin if you want. Once you make your own plugin and publish it, you can advertise it on Reddit. https://www.reddit.com/r/homebridge/ This community is quite active so you can get quick and a lot of feedback on your plugin. You can check a recent post about AppleTV plugin https://www.reddit.com/r/homebridge/comments/17mquj7/apple_tv_enhanced_plugin/ It's been 12 days posted it but there are a lot of comments and the developer attracted a lot of users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants