openhab / openhab-addons

Add-ons for openHAB
https://www.openhab.org/
Eclipse Public License 2.0
1.88k stars 3.59k forks source link

[homekit] Add IrrigationSystem Valve.Name characteristic #15387

Closed lsiepel closed 2 months ago

lsiepel commented 1 year ago

According to https://www.openhab.org/addons/integrations/homekit/ a valve can have a Valve.Name characteristic. But when the valve is part of an irrigation system, this name characteristic is missing/not supported.

Apple Home app allows you to name each zone. It would be nice if this name could be synchronized with openHAB, just as with other name characteristics. This way, my zones will always have the same name in all aps and appearances.

FTR: it is unsupported, but when you do set a Valve.Name to the openHAB item definition, it causes an error: Accessory gr_buiten_achter_irrigatie_klep1 already has a characteristic of type NameCharacteristic; ignoring additional definition.

For reference, this is my current item definition, combined with Gardena binding:

Group   gr_buiten_achter_irrigatie      "Irrigation system"                                                             { homekit="IrrigationSystem" }
String                      irrigationSystemProgramMode                             (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.ProgramMode" }
String                      buiten_achter_irrigatie_naam                            (gr_buiten_achter_irrigatie)        { channel="gardena:irrigation_control:home:buiten_achter_irrigatie:common#name"  }
Group:Switch:AND(ON,OFF)    buiten_achter_irrigatie_enabled     "Enabled"           (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.Active" }
Group:Switch:OR(ON,OFF)     buiten_achter_irrigatie_inuse       "Actief"            (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.InUseStatus" }
String                      buiten_achter_irrigatie_remainingduration                           (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.RemainingDuration" }

Group   gr_buiten_achter_irrigatie_klep1            "Valve 1"           (gr_buiten_achter_irrigatie)                                        { homekit="Valve"[ServiceIndex=1], channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#name" }
String  buiten_achter_irrigatie_klep1_naam          "Klep"              (gr_buiten_achter_irrigatie_klep1)                                  {  homekit="Valve.Name", channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#name" }
String  buiten_achter_irrigatie_klep1_activity      "Actief"                                                                                { channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#activity" }
Switch  buiten_achter_irrigatie_klep1_enabled       "Enabled"           (buiten_achter_irrigatie_enabled,gr_buiten_achter_irrigatie_klep1)  { homekit="Valve.ActiveStatus" }
Switch  buiten_achter_irrigatie_klep1_inuse         "Actief"            (buiten_achter_irrigatie_inuse,gr_buiten_achter_irrigatie_klep1)    { homekit="Valve.InUseStatus" }
Switch  buiten_achter_irrigatie_klep1_stop          "Stop Switch"       (gr_buiten_achter_irrigatie_klep1)                                  { channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne_commands#stop_until_next_task" }
Number  buiten_achter_irrigatie_klep1_duration      "Duration"          (gr_buiten_achter_irrigatie_klep1)                                  { homekit="Valve.Duration"[homekitDefaultDuration = 1800], channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#duration"}
ccutrer commented 2 months ago

Is this resolved now (with 4.3.0-SNAPSHOT) after #17031?

lsiepel commented 2 months ago

Is this resolved now (with 4.3.0-SNAPSHOT) after #17031?

Will test and report back in the next days

lsiepel commented 2 months ago

When starting the new version, i encountered this Exception. Have to investigate further what is going on. Probably some configuration mistake on my end, but i would have hoped for a more descriptive error message so i can identify/correct the problem.

2024-07-24 14:01:19.152 [WARN ] [.server.impl.connections.HttpSession] - Could not handle request
java.lang.IllegalStateException: Duplicate key io.github.hapjava.characteristics.impl.common.NameCharacteristic@185e3cb8 (attempted merging values 5 and 12)
    at java.util.stream.Collectors.duplicateKeyException(Collectors.java:135) ~[?:?]
    at java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:182) ~[?:?]
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) ~[?:?]
    at java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet.lambda$entryConsumer$0(Collections.java:1625) ~[?:?]
    at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1850) ~[?:?]
    at java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntrySetSpliterator.forEachRemaining(Collections.java:1650) ~[?:?]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[?:?]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[?:?]
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[?:?]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[?:?]
    at io.github.hapjava.server.impl.json.AccessoryController.swapKeyAndValue(AccessoryController.java:112) ~[bundleFile:?]
    at io.github.hapjava.server.impl.json.AccessoryController.listing(AccessoryController.java:42) ~[bundleFile:?]
    at io.github.hapjava.server.impl.connections.HttpSession.handleAuthenticatedRequest(HttpSession.java:74) [bundleFile:?]
    at io.github.hapjava.server.impl.connections.ConnectionImpl.doHandleRequest(ConnectionImpl.java:55) [bundleFile:?]
    at io.github.hapjava.server.impl.connections.ConnectionImpl.handleRequest(ConnectionImpl.java:49) [bundleFile:?]
    at io.github.hapjava.server.impl.http.impl.AccessoryHandler.channelRead0(AccessoryHandler.java:52) [bundleFile:?]
    at io.github.hapjava.server.impl.http.impl.AccessoryHandler.channelRead0(AccessoryHandler.java:17) [bundleFile:?]
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) [bundleFile:4.1.104.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) [bundleFile:4.1.104.Final]
    at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61) [bundleFile:4.1.104.Final]
    at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:425) [bundleFile:4.1.104.Final]
    at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173) [bundleFile:4.1.104.Final]
    at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66) [bundleFile:4.1.104.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) [bundleFile:4.1.104.Final]
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [bundleFile:4.1.104.Final]
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [bundleFile:4.1.104.Final]
    at java.lang.Thread.run(Thread.java:840) [?:?]

As soon as i uncomment the line with the name IrrigationSystem.Name characteristic the binding starts throwing the above error.

Group   gr_buiten_achter_irrigatie      "Irrigation system"                                                             { homekit="IrrigationSystem" }
String                      buiten_achter_irrigatie_program     "Program mode [%s]" (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.ProgramMode" }
//String                        buiten_achter_irrigatie_naam                            (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.Name",channel="gardena:irrigation_control:home:buiten_achter_irrigatie:common#name"  }
Group:Switch:AND(ON,OFF)    buiten_achter_irrigatie_enabled     "Enabled"           (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.Active" }
Group:Switch:OR(ON,OFF)     buiten_achter_irrigatie_inuse       "Klep open"         (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.InUseStatus" }
Number                      buiten_achter_irrigatie_remaining   "Total remaining [%s]"                  (gr_buiten_achter_irrigatie)        { homekit="IrrigationSystem.RemainingDuration" }

Group   gr_buiten_achter_irrigatie_klep1            "Valve 1"           (gr_buiten_achter_irrigatie)                                        { homekit="Valve"[ServiceIndex=1], channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#name" }
String  buiten_achter_irrigatie_klep1_naam          "Klep"              (gr_buiten_achter_irrigatie_klep1)                                  { homekit="Valve.Name", channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#name" }
String  buiten_achter_irrigatie_klep1_activity      "Activiteit"                                                                            { channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#activity" }
Switch  buiten_achter_irrigatie_klep1_enabled       "Enabled"           (buiten_achter_irrigatie_enabled,gr_buiten_achter_irrigatie_klep1)  { homekit="Valve.ActiveStatus" }
Switch  buiten_achter_irrigatie_klep1_inuse         "Klep open"         (buiten_achter_irrigatie_inuse,gr_buiten_achter_irrigatie_klep1)    { homekit="Valve.InUseStatus" }
Switch  buiten_achter_irrigatie_klep1_stop          "Stop Switch"       (gr_buiten_achter_irrigatie_klep1)                                  { channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne_commands#stop_until_next_task" }
Number  buiten_achter_irrigatie_klep1_duration      "Opdr. duration"    (gr_buiten_achter_irrigatie_klep1)                                  { homekit="Valve.Duration"[homekitDefaultDuration=1800]}
Number  buiten_achter_irrigatie_klep1_remaining     "Remaining [%s]"    (gr_buiten_achter_irrigatie_klep1)                                  { channel="gardena:irrigation_control:home:buiten_achter_irrigatie:valveOne#duration"}
Number  buiten_achter_irrigatie_klep1_hkremaining   "Remaining [%s]"    (gr_buiten_achter_irrigatie_klep1)                                  { homekit="Valve.RemainingDuration"}

With the commented out line, the home app works i do see the irrigation system, but the valve is nowhere to be found. No errors or message in the openhab.log

ccutrer commented 2 months ago

Oooh yeah, that's not good. Even with a bad configuration, the openHAB code should be catching it long before we get an exception inside of HAP-Java. I tested the Accessory Information Service commit a decent amount, but it's quite possible I missed a configuration case with IrrigationService, since it behaves a bit differently wrt linked services.

lsiepel commented 2 months ago

Let me know if you need more details. Somehow i can't get the irrigation to work.

  1. When the item with homekit="IrrigationSystem.Name" is added, it gives excpetion.
  2. When a valve is added, no exception or (info/warn/error) logging and all home app items become unresponsive.
ccutrer commented 2 months ago

Fix pushed. With your example config, I see the valve in my Home. Unfortunately (and I think I remember this when I first implemented linked services/irrigation system), Home ignores the name characteristic on the valve (at least on iOS 18 Beta 4). And even if it didn't, it definitely wouldn't keep them in sync - Name is not evented (so openHAB can't notify Home when the value changes), isn't writable (so changes in Home can't be propagated back to openHAB), and AFAICT even after a reconnect, ignores any changes to its value.