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

[pwm] Initial Contribution #10205

Merged
merged 9 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/bundles/org.openhab.automation.groovyscripting/ @wborn
/bundles/org.openhab.automation.jythonscripting/ @openhab/add-ons-maintainers
/bundles/org.openhab.automation.pidcontroller/ @fwolter
/bundles/org.openhab.automation.pwm/ @fwolter
/bundles/org.openhab.binding.adorne/ @theiding
/bundles/org.openhab.binding.airquality/ @kubawolanin
/bundles/org.openhab.binding.airvisualnode/ @3cky
Expand Down
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<artifactId>org.openhab.automation.pidcontroller</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.automation.pwm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.adorne</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.automation.pwm/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.

* Project home: https://www.openhab.org

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/openhab/openhab-addons
62 changes: 62 additions & 0 deletions bundles/org.openhab.automation.pwm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Pulse Width Modulation (PWM) Automation

This automation module implements [Pulse Width Modulation (PWM)](https://en.wikipedia.org/wiki/Pulse-width_modulation).

PWM can be used to control actuators continuously from 0 to 100% that only support ON/OFF commands.
E.g. valves or heating burners.
It accomplishes that by switching the actuator on and off with a fixed interval.
The higher the control percentage (duty cycle), the longer the ON phase.

Example: If you have an interval of 10 sec and the duty cycle is 30%, the output is ON for 3 sec and OFF for 7 sec.

Copy link
Contributor

@Skinah Skinah Feb 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel a warning is necessary about relay contact life expectancy. If this example was done for a full year it would be over 1.3 Million contact cycles which would wear most cheap devices out and make even quality units fail.

This module is **unsuitable** for controlling LED lights as the high PWM frequency can't be met.

> Note: The module starts to work only if the duty cycle has been updated at least once.

## Modules

The PWM module can be used in openHAB's [rule engine](https://www.openhab.org/docs/configuration/rules-dsl.html).

This automation provides a trigger module ("PWM triggers") with one input Item: `dutycycleItem` (0-100%).
The module calculates the ON/OFF state and returns it.
The return value is used to feed the Action module "Item Action" aka "send a command", which controls the actuator.

To configure a rule, you need to add a Trigger ("PWM triggers") and an Action ("Item Action").
Select the Item you like to control in the "Item Action" and leave the command empty.

### Trigger

| Name | Type | Description | Required |
|-----------------|---------|----------------------------------------------------------------------------------------------|----------|
| `dutycycleItem` | Item | The Item (PercentType) to read the duty cycle from | Yes |
| `interval` | Decimal | The constant interval in which the output is switch ON and OFF again in sec. | Yes |
| `minDutyCycle` | Decimal | Any duty cycle below this value will be increased to this value | No |
| `maxDutycycle` | Decimal | Any duty cycle above this value will be decreased to this value | No |
| `deadManSwitch` | Decimal | The output will be switched off, when the duty cycle is not updated within this time (in ms) | No |

The duty cycle can be limited via the parameters `minDutycycle` and `maxDutyCycle`.
This is helpful if you need to maintain a minimum time between the switching of the output.
This is necessary for example for heating burners, which may not be switched on for very short times.
The on time is than increased to `minDutycycle`.
In this case one should also set a max duty cycle to prevent short off times.
It makes sense to apply these symmetrically e.g. 10%/90% or 20%/80%.

If the duty cycle is 0% or 100%, the min/max parameters are ignored and the output is switched ON or OFF continuously.

If the duty cycle Item is not updated within the dead-man switch timeout, the output is switched off, regardless of the current duty cycle.
The function can be used to save energy if the source of the duty cycle died for whatever reason and doesn't update the value anymore.
When the duty cycle is updated again, the module returns to normal operation.

> Note: The min/max ON/OFF times set via `minDutycycle` and `maxDutycycle` are not met if the dead-man switch triggers and recovers fast.

## Control Algorithm

This module is designed to respond fast to duty cycle changes, but at the same time maintain a constant interval and also the min/max ON/OFF parameters.
For that reason, the module might seem to act peculiarly in some cases:

- When the output is ON and the duty cycle is decreased, the output might switch off immediately, if applicable.
Example: The interval is 10 sec and the current duty cycle is 80%.
When the duty cycle is decreased to 20%, the output would switch off immediately, if it has been already ON for more than 2 sec.
- When the duty cycle is 0% for a short interval and then increased again, the output will only switch on when the new interval starts.
- When the duty cycle is 0% or 100% for more than a whole interval, a new interval will start as soon as the duty cycle is updated to a value other than 0%, respective 100%.
- The module starts to work only if the duty cycle Item has been updated at least once.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions bundles/org.openhab.automation.pwm/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.1.0-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.automation.pwm</artifactId>

<name>openHAB Add-ons :: Bundles :: Automation :: PWM</name>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.automation.pwm-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>

<feature name="openhab-automation-pwm" description="PWM Automation" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.automation.pwm/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.automation.pwm.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* Constants for the PWM automation module.
*
kaikreuzer marked this conversation as resolved.
Show resolved Hide resolved
* @author Fabian Wolter - Initial Contribution
*/
@NonNullByDefault
public class PWMConstants {
public static final String AUTOMATION_NAME = "pwm";

public static final String CONFIG_DUTY_CYCLE_ITEM = "dutycycleItem";
public static final String CONFIG_PERIOD = "interval";
public static final String CONFIG_MIN_DUTYCYCLE = "minDutycycle";
public static final String CONFIG_MAX_DUTYCYCLE = "maxDutycycle";
public static final String CONFIG_COMMAND_ITEM = "command";
public static final String CONFIG_DEAD_MAN_SWITCH = "deadManSwitch";
public static final String CONFIG_OUTPUT_ITEM = "outputItem";
public static final String INPUT = "input";
public static final String OUTPUT = "command";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.automation.pwm.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* Common exception for the PWM automation module.
*
* @author Fabian Wolter - Initial Contribution
*/
@NonNullByDefault
public class PWMException extends Exception {
private static final long serialVersionUID = -3029834022610530982L;

public PWMException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.automation.pwm.internal.factory;

import java.util.Collection;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.automation.pwm.internal.handler.PWMTriggerHandler;
import org.openhab.core.automation.Module;
import org.openhab.core.automation.Trigger;
import org.openhab.core.automation.handler.BaseModuleHandlerFactory;
import org.openhab.core.automation.handler.ModuleHandler;
import org.openhab.core.automation.handler.ModuleHandlerFactory;
import org.openhab.core.items.ItemRegistry;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* Factory for the PWM automation module.
*
* @author Fabian Wolter - Initial Contribution
*/
@NonNullByDefault
@Component(service = ModuleHandlerFactory.class, configurationPid = "automation.pwm")
public class PWMModuleHandlerFactory extends BaseModuleHandlerFactory {
private static final Collection<String> TYPES = Set.of(PWMTriggerHandler.MODULE_TYPE_ID);
private ItemRegistry itemRegistry;
private BundleContext bundleContext;

@Activate
public PWMModuleHandlerFactory(@Reference ItemRegistry itemRegistry, BundleContext bundleContext) {
this.itemRegistry = itemRegistry;
this.bundleContext = bundleContext;
}

@Override
public Collection<String> getTypes() {
return TYPES;
}

@Override
protected @Nullable ModuleHandler internalCreate(Module module, String ruleUID) {
switch (module.getTypeUID()) {
case PWMTriggerHandler.MODULE_TYPE_ID:
return new PWMTriggerHandler((Trigger) module, itemRegistry, bundleContext);
}

return null;
}
}
Loading