Mapping actions of the FP1 presence sensor onto OH items

Wow, thanks for all the work!

Unfortunately, changing the regex to region_1_(.*) didn’t solve it for me. It would have surprised me since that transformation (from mqtt-topic value to channel value) works fine. It is the next transformation that fails:

2024-01-15 11:42:26.448 [WARN ] [al.profiles.MapTransformationProfile] - Could not transform state 'enter' with function 'FP1_states.map' and format '%s'

Did you have the file FP1_states.map located in <CONF>/transform/ folder ?

To change the logger config, go to Karaf console, and type

log:set debug org.openhab.transform.map.internal.profiles.MapTransformationProfile

When you’re done, type:

log:set default org.openhab.transform.map.internal.profiles.MapTransformationProfile

EDIT: However, looking at the source code, you probably won’t get much more details because the exception is masked :frowning:

yes, it’s in the same folder as the de.map and en.map files that seem to be included by default. However, while those files show up in the UI, the one I created doesn’t:

Safari-2024-01-15 at 11.57.24@2x

But there is no error that it cant find the file, so I assume that it is reading it w/o problems.

Hmm… pardon me, that \w+ indeed worked. I fell victim of not escaping the backslash (I entered mine in code editor - yours is fine because it’s entered on the web ui)

Anyhow, I can now get mine to work fine with \w+ pattern too.

Have you tried renaming the file (and updating the file reference in the profile settings)?
I am suspecting that the file somehow didn’t get loaded properly by the file watcher (for some reason - if this was the case, then it’s a bug). By renaming, hopefully the file watcher would notice it and load it.

I’m still working on figuring out the console. Had to find out the default password for the openhab user on the docker image (answer is here).

But this sounds more promising:

You mean just rename it to something else?

What file reference in what profile settings?

Edit: I think I found the problem:

>ll
drwxr-xr-x 15 9001 9001 4096 Dec 22  2021 ../
-rw-------  1 root root   41 Jan 15 10:15 FP1_states.map
-rw-------  1 9001 9001   38 Dec 13  2020 de.map
-rw-------  1 9001 9001   38 Dec 13  2020 en.map
-rw-------  1 9001 9001  282 Dec 13  2020 readme.txt

Yes just rename it to e.g. occupancy_states.map

This one - see where it says FP1_states.map - change that to match the new name

Alternatively try restarting openhab - that should reload the map files too.

Bingo!
I wish the error message included the actual problem instead of just sugar coating it with a generic “sorry it didn’t work”.

1 Like

OK, I got it to work. The problem was the file permission:

chowned it to 9001:9001 and now it works.

Thanks for all your help!

Oh, of course. Didn’t realize that was called a profile.

That I don’t understand. It can’t be an alternative to changing the file name in the profile, cause how would it know that the file is now called something else, so do you mean this is an alternative to renaming? In that case, could you explain what exactly your diagnosis was? Are you saying that openhab may simply have missed that this file exists and wouldn’t even find it when provided its name and that restarting OH or renaming the file would trigger it to see that file? I’m asking this because it seems to be an important mechanism to be aware of when troubleshooting OH, i.e. that files need to be somehow picked up by OH in order for it to access them, cause it can’t see them based on the path alone, or something?

Yes I meant alternative to renaming. But given the actual problem, that wouldn’t have helped.

No, I thought that for some reason when you created the file, openhab didn’t “notice” that this file existed, so it wouldn’t load it. And because it wasn’t loaded, it wouldn’t have found it when you’re referring to it in your transformation. This is because I have read in some cases the file watcher failed when symlinks are involved.

As we now know, that wasn’t the case, but it’s kinda related, i.e. openhab couldn’t load the file due to permissions.

It sounds like you are heading down a good path. I just wanted to add a couple of comments.

Option 1: This is the best approach when the publisher misuses MQTT by sending large JSON messages instead of publishing to separate topics. One of the guiding principles of MQTT is “thou shall not impose work on your subscribers.” Requiring subscribers to receive and parse a JSON string is an imposition. Remember, MQTT was designed to work with underpowered microcontrollers in a spotty networking environment.

Option 2: This won’t work, as you surmise.

Option 3: This is a last option when Option 1 and Option 4 are not possible. Option 1 can sometimes not be possible if the JSON sent includes a not-fixed size array. The JSONPATH transform is not flexible enough to handle that case.

Option 3a: A Script transformation could be used instead of a Rule in some cases.

Option 0: This is the more MQTT way to solve this problem. zigbee2mqtt should not impose work on it’s subscribers.

So the “right way”, from an MQTT perspective is Option 0. Failing that, Option 1 is next best followed by one of the Option 3s.

1 Like

Thanks for the additional comments.

Yes, I also noticed that when I tried to implement it.

Yes, this is not ideal, but I’m thankful that someone actually took the time to program zigbee2mqtt to read the FP1 sensor in general, and its zones in particular. I’m not sure why they chose this path, but I assume it was easier to implement and/or a way of avoiding other pitfalls.

I now realized that they not only squeezed the actions recorded in up to ten zones into a single mqtt topic but also two types of actions/status that could have been much more conveniently in two separate switch topics: leave/enter and occupied/unoccupied. Unless I’m misunderstanding how these work, these pairs are about quite different things: the leave or enter event triggers every time someone leaves or enters the zone in question, i.e. it signals an event, and occupied/unoccupied topic is about the state of the zone.

So, I’m not sure what might be the benefits of putting all of that into a single topic, but maybe there is something about having one topic instead of twenty (10 zones x 2 topics). But even two topics instead of one would have made more sense.

Yes, so maybe another explanation could be that zigbee2mqtt actually has some built-in magic specialized on modifying the default topics, e.g. by splitting up a given topic into multiple topics or sub-topics or something, but I didn’t want to dig into that. Rather took the opportunity to learn more about OH.

I’m almost certain it does and it’s a simple configuration setting. I’ll be way less work over all to configure that.

I’ll see if I can figure it out.

For now, I’m wondering how I can use maps in OH so that certain inputs are simply ignored. I have created two maps:

exit-enter.map:

enter=1
leave=-1

and occupied.map:

unoccupied=0
occupied=1

believing that each map will ignore the states that it can’t map, but this is apparently not the case:

2024-01-19 20:12:02.716 [WARN ] [al.profiles.MapTransformationProfile] - Could not transform state 'occupied' with function 'enter-exit.map' and format '%s'

So, I take it that a map must cover all possible input values. So, is there a way of telling it “if this value comes in, do nothing”, i.e. not update to null or anything, just keep the previous value?

The answer is here:

A default value can be provided if no matching entry is found by using “=value” syntax. Defining this default value using _source_ would then return the non transformed input string.

OK, so if that page is documenting all possibilities, then the answer is: no, it’s not possible. I’ll have to either use a rule or figure out how to do it in zigbee2mqtt…

I’m not sure about your interpretation of these actions as independent pairs. I think they’re an ordered sequence, because only one can be possible at any time:

enteroccupiedleaveunoccupiedenter → etc.

If there are two people in the room and one person leaves, the FP1 won’t change to leave, because the room is still occupied. And if the other person comes back, it shouldn’t trigger enter, because the room is already occupied. When both people exit, it changes to leave and then unoccupied.

That’s exactly what you want from an automation perspective: turn on the lights when two people enter a room, but don’t turn off the lights when one person leaves. Then turn off the light when the second person leaves.

I might be wrong about this. If you haven’t already done so, the easy way to test would be to carry out the scenario above with two people and see whether or not the enter/leave events are triggered.

If my interpretation is correct, 10 separate regions would be best. As it is, if multiple regions change at the same time it’s going to spam a lot of state changes right on top of each other. They shouldn’t ever conflict, but state changes could get missed. You might want to file a change request with Zigbee2mqtt.

In any case, I’ll be curious to hear how well it works for you. I’ve been thinking about trying out a presence sensor.

I haven’t tested it, but I think you’re right. Thanks for pointing this out.

Yes, that’s exactly the issue I’m trying to solve. And yes, 10 regions it is, not 20. In fact, 3 is enough for me, but the sensor can handle up to 10.

I can’t seem to figure this out in zigbee2mqtt, but I think I should be able to get it to work in OH, now that I’m no longer trying to split leave/enter from occupied/unoccupied). I’m now using region_1_(\w+), region_2_(\w+), and region_3_(\w+) in the profile for three items.

Actually, I thought that would work, but it looks like I have the same problem as with the maps above: if the regex captures nothing (because the event concerned a differemnt region), the item state becomes empty (not NULL), so it looks like the issue can’t be solved with transformations. I’ll have to use rules after all…

Personally, I’d just use a rule to update unbound items for each region. It’s less sophisticated, but easier for me to wrap my head around.

No, try this as your transformation:

REGEX:region_1.*∩REGEX:region_1_(\w+)

I think that should do what you want.