Automation for lowering/raising shade

So I’ve got a Somfy shade integrated in and I’d like to control it via an automation. I also have integrated in my solar system and my weather station. Here’s what I’d like to do:

  1. Lower the shade when the solar system sees a threshold of power produced (i.e. the sun is out).
  2. Raise the shade when the wind gets above xx mph. (perhaps relower it if it stays down for longer than Y minutes)
  3. raise the shade at 11:30AM regardless (the sun is no longer on that window).
  4. I’d like to be able to raise the shade manually if I decide I want to look out the window and not have the system immediately override me because of #1.

I think I can probably code this myself (albeit I’m a bit flummoxed on #4), but there are a lot of corner cases here I want to make sure I take care of and I’m not totally fluent on HA coding, so any guidance or suggestions for things I’ve missed, I’d love to hear.

give the code a try and if you hit troubles and need help, post the code you’ve got.

#4 shoudln’t be an issue because triggers happen when a value goes from false to true. so if you manually open the shade, #1 will only kick and close it the next time the solar system sees the power cross to the threshold. the main followup question for #4 is … when do you want to close it after you manually open it? do you want to just let things go to the next cycle? or do you want to close it after some timeout? or??

Take a look at this thread, it can give you some clues on how to go further. There’s also an integration, but it doesn’t take the wind speed into account. But you can find a blueprint in this thread, that you might use as a starting point. The blueprint grew into an integration, but is still available and maintained! :slight_smile:

1 Like

So one of the problems I know I’ll have is that the Somfy myLink integration doesn’t poll the myLink device periodically, so I get no notification that I used the shade remote to retract the shade. There may be no “state” variable available as even the somfy app doesn’t seem to know if the shade is up or down. So I guess I’ll have to toss the remote and make sure all shade movement is done through Home Assistant somehow.

Is there a moving/rolling average or a rolling min/max function in Home Assistant? I’d like to raise the shade the instant I see any wind over 15mph, but retrigger the lowering if my maximum wind is below 15 for the past 10 minutes.

If you are controlling RTS motors you can use ESPSomfy RTS to maintain state and control your motors whether it was moved by an integration, handheld remote, or another 3rd party controller. Since the integration creates cover entities you can use them with automations such as the one mentioned above.

So here’s my code. I’d love some critique on if I missed anything:
I started by creating a statistic that keeps track of the maximum wind gust over the last 10 minutes:

sensor:
  - platform: statistics
    name: wind_gust_max
    entity_id: sensor.wind_gust
    sampling_size: 100 
    state_characteristic: max
    max_age:
      minutes: 10

Next I created an automation to lower the shade at 30W of power on the panel:

- id: '1723335193245'
  alias: shade_lower
  description: Lower the shade in the morning when the sun hits the panels
  trigger:
  - platform: numeric_state
    entity_id:
    - sensor.envoy_121640037391_inverter_121602030869
    above: 30
  - platform: numeric_state
    entity_id:
    - sensor.wind_gust_max
    below: 25
  condition:
  - condition: time
    before: '11:30:00'
  - condition: numeric_state
    entity_id: sensor.envoy_121640037391_inverter_121602030869
    above: 30
  - condition: numeric_state
    entity_id: sensor.wind_gust_max
    below: 25
  action:
  - device_id: 44058007bb965bb2ab223ef9f0cccf67
    domain: cover
    entity_id: 6686ca44d3e87545cbd48e8600b541b8
    type: close
  mode: single

Then I created one to raise the shade if the wind gust gets too high:

- id: '1723333587644'
  alias: shade_retract_for_wind
  description: Retract Great Room Shade if wind is too high
  trigger:
  - platform: numeric_state
    entity_id:
    - sensor.wind_gust
    above: 25
  condition: []
  action:
  - device_id: 44058007bb965bb2ab223ef9f0cccf67
    domain: cover
    entity_id: 6686ca44d3e87545cbd48e8600b541b8
    type: open
  mode: single

And finally the one to raise the shade at 11:30am

- id: '1723335503574'
  alias: shade_retract_for_time
  description: 'Retract great room shade at a specific time'
  trigger:
  - platform: time
    at: '11:30:00'
  condition: []
  action:
  - device_id: 44058007bb965bb2ab223ef9f0cccf67
    domain: cover
    entity_id: 6686ca44d3e87545cbd48e8600b541b8
    type: open
  mode: single

There are some things I don’t like about this:

  1. What’s up with that device_id, entity_id stuff in the actions? I have an entity_id defined for that shade. I wonder why the GUI didn’t use it.
  2. I don’t really like that the time is defined in two differet places, the wind_gust threshold is defined in 3 places, and the panel wattage threshold is defined in two places; but I don’t really know how to unify those into global variables.
  3. There’s a bit of a corner case where the wind gust triggers when the wind_gust is “above” 25, but the shade_lower triggers when the wind_gust_max is “below” 25. So there’s a situation where the wind_gust can be exactly 25 and it escapes both scripts. However, that shouldn’t be a big deal because doing nothing in that case is just fine.
  4. However! There is a race condition here where a wind gust could come along above 25, we could evaluate the retract and fire, we could then evaluate the lower and fire (because we have not yet updated our statistic for the wind_gust_max), and then we update the statistic for wind_gust_max. Probably impossibly unlikely, but it still feels like a problem.

1: in the gui, select entity instead of device. if you select device, it’ll do whaty ou have. if you select entity, it’ll use the friendly name.

2 & 3: create a binary_sensor helper with

{{ states('sensor.wind_gust') } int < 25 }}

and use that being on/off instead of what you currently have. this consolidates the checks for wind_gust into this one sensor and also changes to trigger when wind_gust is above or equal to 25, which solves your #3.

4: sorry i don’t quite understand this description.

Thanks. #4 is so obscure I’m not going to worry about it.

Let me ask this. I have defined a helper sensor (wind_gust_max) for maximum wind gust over a 10 minute period using the statistics functions and then I use that in my automations as both a trigger and a condition. I notice there’s a “for” option in the automation trigger and conditions. If I throw away my helper sensor (wind_gust_max) and use the ‘for 00:10:00’ field in the trigger/condition on the source entity (wind_gust), will that behave exactly the same as what I have?

If you put a for: 0:10:00 the trigger will only happen when it becomes and stays in the expected condition for 10 continuous minutes

I don’t see any existing code of yours doing that so I can’t say that it will do exactly what you currently have

I had defined this sensor (wind_gust_max) which calculates the maximum wind_gust over the previous 10 minutes.

sensor:
  - platform: statistics
    name: wind_gust_max
    entity_id: sensor.wind_gust
    sampling_size: 100 
    state_characteristic: max
    max_age:
      minutes: 10

Then I used it in my trigger and condition:

  trigger:
  - platform: numeric_state
    entity_id:
    - sensor.wind_gust_max
    below: 25

and my condition

  condition:
  - condition: numeric_state
    entity_id: sensor.wind_gust_max
    below: 25

I believe this is entirely the same as (but I’m not sure of??) eliminating the wind_gust_max sensor and defining my trigger as:

  trigger:
  - platform: numeric_state
    entity_id:
    - sensor.wind_gust
    for:
      hours: 0
      minutes: 10
      seconds: 0
    below: 25

and my condition as:

  - condition: numeric_state
    entity_id: sensor.wind_gust
    below: 25
    for:
      hours: 0
      minutes: 10
      seconds: 0

the ‘for’ will require it to be above 25 for the entirety of the 10 minutes, which is different than finding that the max was above 10 during the last 10 minutes. so they are not exactly equivalent, but perhaps it’s all you need?