# How to use "ctrlIoChannelSingleThreshold0"?

**URL:** <https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703>\
**Category:** English Forum\
**Created:** [January 8, 2026, 7:29pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703 "2026-01-08T19:29:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![sjjh](https://community.openems.io/user_avatar/community.openems.io/sjjh/32/2296_2.png) [@sjjh](https://community.openems.io/u/sjjh)\
**Post date:** [January 8, 2026, 7:29pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/1 "2026-01-08T19:29:36Z")

</div>

We would like to [switch a consumer on/off](https://community.openems.io/t/recommendation-for-a-high-voltage-contactor/10670) depending on the electricity cost. We are using a _Shelly Pro 3_ as contractor for the three phases, the `ctrlIoChannelSingleThreshold` as controller and the `timeOfUseTariff` component for the price.  
The controller is configured as depicted in the screenshot:

 ![screenshot](https://community.openems.io/uploads/default/original/2X/4/4c0c7c194e7284a78419921d1d357107b4dd31eb.png)

But the controller seems not to work, the debug log shows:

```auto
8.1.2026, 18:34:55
WARN
io.openems.edge.core.cycle.CycleWorker
[_cycle] Error in Controller [ctrlIoChannelSingleThreshold0]. ClassCastException: class io.openems.edge.common.channel.DoubleReadChannel cannot be cast to class io.openems.edge.common.channel.IntegerReadChannel (io.openems.edge.common.channel.DoubleReadChannel and io.openems.edge.common.channel.IntegerReadChannel are in unnamed module of loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @3316dc5f)

```

We also tried to specify the _Threshold_ as `300` instead of `300.0`, leading to the same result.

We additionally noted, that the channel `_sum/GridBuyPrice` uses `€/MWh` and the log uses `€/kWh` – we assumed, that the channel value is more relevant, thus using the threshold value of `300` (as `€/MWh`).

Can someone please give a hint what’s going wrong? Thx for any help!  
Simon

PS: The meaning of the **Mode** (default: `automatic`) within the controller isn’t clear to us. Can someone explain it to us?

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 8, 2026, 8:54pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/2 "2026-01-08T20:54:17Z")

</div>

The problem is not the entered threshold value, but the type of the input channel.

`_sum/GridBuyPrice` is of type `DoubleReadChannel`

but the input channel of a `ControllerIoChannelSingleThreshold` has to be of type `IntegerReadChannel`:

`IntegerReadChannel inputChannel = ` **`this`** `.componentManager.getChannel(inputChannelAddress);`

Maybe the variable inputChannel should be changed to DoubleReadChannel and there should be a handler that determines the input channel type and converts the value to Double.

---

<div class="post-metadata">

**Author:** ![sjjh](https://community.openems.io/user_avatar/community.openems.io/sjjh/32/2296_2.png) [@sjjh](https://community.openems.io/u/sjjh)\
**Post date:** [January 8, 2026, 11:38pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/3 "2026-01-08T23:38:55Z")

</div>

Thx for your reply!

> [@s\_h](#):
>
> Maybe the variable inputChannel should be changed to DoubleReadChannel and there should be a handler that determines the input channel type and converts the value to Double.

I created a PR (I believe an explicit cast is not needed, as integer, long, float get implicitly casted to double):

> <https://github.com/OpenEMS/openems/pull/3510>
>
> …m Integer to Double
> 
> Now the controller also works with input channel \`\_sum/G…ridBuyPrice\`; cf. https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/2

Still looking for some insights for this: 🙂

> [@sjjh](#):
>
> PS: The meaning of the **Mode** (default: `automatic`) within the controller isn’t clear to us. Can someone explain it to us?

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 9, 2026, 8:13am UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/4 "2026-01-09T08:13:28Z")

</div>

> [@sjjh](#):
>
> I created a PR (I believe an explicit cast is not needed, as integer, long, float get implicitly casted to double):
> 
> [ControllerIoChannelSingleThresholdImpl.java: Changed inputChannel fro… by sjjh · Pull Request #3510 · OpenEMS/openems · GitHub](https://github.com/OpenEMS/openems/pull/3510)

I don’t think this is enough. The threshold is still int and the comparison is done with integers:

```auto
		int inputValue;
		if (inputValueOpt.isPresent()) {
			inputValue = (int) Math.round(inputValueOpt.getAsDouble());
...
			if (inputValue <= this.config.threshold())
...
			if (inputValue > this.config.threshold()) {
...

```

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 9, 2026, 8:20am UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/5 "2026-01-09T08:20:05Z")

</div>

> [@sjjh](#):
>
> Still looking for some insights for this: 🙂
> 
> > [@sjjh](#):
> >
> > PS: The meaning of the **Mode** (default: `automatic`) within the controller isn’t clear to us. Can someone explain it to us?

The switch can be manually set in the GUI [https://docs.fenecon.de/en/fems/fems-app/App\_Schwellwertsteuerung.html](https://docs.fenecon.de/en/fems/fems-app/App_Schwellwertsteuerung.html)

```auto
	public void run() throws OpenemsNamedException {
		var outputChannels = this.getOutputChannels();

		switch (this.config.mode()) {
		case ON:
			this.setOutputs(outputChannels, true);
			break;
		case OFF:
			this.setOutputs(outputChannels, false);
			break;
		case AUTOMATIC:
			this.automaticMode(outputChannels);
			break;
		}
	}

```

---

<div class="post-metadata">

**Author:** ![sjjh](https://community.openems.io/user_avatar/community.openems.io/sjjh/32/2296_2.png) [@sjjh](https://community.openems.io/u/sjjh)\
**Post date:** [January 9, 2026, 11:35am UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/6 "2026-01-09T11:35:35Z")

</div>

> [@s\_h](#):
>
> The switch can be manually set in the GUI

This was the piece of information I was missing.  
What would be the use case to specify something different than `automatic` during setting up the component? There I did find the drop-down (without any further documentation) and was a little confused.

> [@s\_h](#):
>
> [https://docs.fenecon.de/en/fems/fems-app/App\_Schwellwertsteuerung.html:](https://docs.fenecon.de/en/fems/fems-app/App_Schwellwertsteuerung.html:)

I created a PR to add a link to the documentation to the readme: [Update readme.adoc: added link to documentation by sjjh · Pull Request #3511 · OpenEMS/openems · GitHub](https://github.com/OpenEMS/openems/pull/3511)

---

<div class="post-metadata">

**Author:** ![sjjh](https://community.openems.io/user_avatar/community.openems.io/sjjh/32/2296_2.png) [@sjjh](https://community.openems.io/u/sjjh)\
**Post date:** [January 9, 2026, 11:40am UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/7 "2026-01-09T11:40:48Z")

</div>

> [@s\_h](#):
>
> I don’t think this is enough. The threshold is still int and the comparison is done with integers:
> 
> ```auto
> int inputValue;
> if (inputValueOpt.isPresent()) {
> inputValue = (int) Math.round(inputValueOpt.getAsDouble());
> ...
> if (inputValue <= this.config.threshold())
> ...
> if (inputValue > this.config.threshold()) {
> ...
> 
> ```

The comparison already included the `(int) Math.round(inputValueOpt.getAsDouble())`, in my understanding already accepting a `Double` and intentionally casting it to an `int`. Thus I thought it would be fine to keep it. Do you believe it would be better to not `round()` the value and compare as `Double`? I’m not understanding the domain/business logic enough to make an informed decision, thus needing some feedback. I’m happy to alter my PR. 🙂

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 9, 2026, 1:50pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/8 "2026-01-09T13:50:26Z")

</div>

> [@sjjh](#):
>
> The comparison already included the `(int) Math.round(inputValueOpt.getAsDouble())`, in my understanding already accepting a `Double` and intentionally casting it to an `int`. Thus I thought it would be fine to keep it.

In my eyes comparing Doubles as Ints doesn’t make sense, even if the loss of precision seems not much. If someone wants a very precise threshold, the system should not tell him “of course you can enter this value, but unfortunately the comparison doesn’t consider it completely“.

If comparing power, energy or prices it may be neglect-able, but maybe there are some other cases where this would be an unwanted limitation.

The component seems originally to be built for power, so there should be done more to adapt it to any unit, at least in the front end, where “W” seems to be hard coded at some places.

---

<div class="post-metadata">

**Author:** ![sjjh](https://community.openems.io/user_avatar/community.openems.io/sjjh/32/2296_2.png) [@sjjh](https://community.openems.io/u/sjjh)\
**Post date:** [January 9, 2026, 4:10pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/9 "2026-01-09T16:10:09Z")

</div>

> [@s\_h](#):
>
> In my eyes comparing Doubles as Ints doesn’t make sense, even if the loss of precision seems not much. If someone wants a very precise threshold, the system should not tell him “of course you can enter this value, but unfortunately the comparison doesn’t consider it completely“.

Fair enough, I’ll try to improve the PR.

> [@s\_h](#):
>
> at least in the front end, where “W” seems to be hard coded at some places.

Noticed that and some other UI issues as well. Will create an additional ticket for these.

_Edit:_ Updated my [PR 3510](https://github.com/OpenEMS/openems/pull/3510). @s_h I would be happy if you can have a look.

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 9, 2026, 7:32pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/10 "2026-01-09T19:32:40Z")

</div>

> [@sjjh](#):
>
> _Edit:_ Updated my [PR 3510](https://github.com/OpenEMS/openems/pull/3510). @s_h I would be happy if you can have a look.

These are exactly the same changes I did in my version, but without testing.

---

<div class="post-metadata">

**Author:** ![sjjh](https://community.openems.io/user_avatar/community.openems.io/sjjh/32/2296_2.png) [@sjjh](https://community.openems.io/u/sjjh)\
**Post date:** [January 9, 2026, 8:00pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/11 "2026-01-09T20:00:21Z")

</div>

> [@s\_h](#):
>
> I did in my version, but without testing.

Sorry, I didn’t see your version.  
I did test my changes locally with my use case and it runs without any exceptions.

It seems that the CI build in the PR fails, but I don’t really understand why.

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 9, 2026, 8:46pm UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/12 "2026-01-09T20:46:40Z")

</div>

> [@sjjh](#):
>
> Sorry, I didn’t see your version.

Oh no, this was a misunderstanding. I’ve made these changes in my local version, just to see if the compiler has any complaints. There is no pull request ore something else.

---

<div class="post-metadata">

**Author:** ![s\_h](https://community.openems.io/letter_avatar_proxy/v4/letter/s/85e7bf/32.png) [@s\_h](https://community.openems.io/u/s_h)\
**Post date:** [January 11, 2026, 9:21am UTC](https://community.openems.io/t/how-to-use-ctrliochannelsinglethreshold0/10703/13 "2026-01-11T09:21:25Z")

</div>

I’ve made a PR for the UI:

[https://github.com/OpenEMS/openems/pull/3515](https://github.com/OpenEMS/openems/pull/3515)
