Searching for a simple wireless orientation/tilt sensor

Hello,

I am looking for a wireless sensor that detects its own orientation, so it can recognize when it is upside down. The most likely that fit my needs seems to be a tilt sensor, but I am not finding any that is cheap or doesn’t require assembly (I’m finding single module for Arduino board, but I don’t have the skills required)

The use case is this: the roborock sometimes get stuck between the legs of the kitchen stool because it doesn’t handle well the shape (wide low base with single leg), so I created a new zone called “undertable” to be avoided when the stool are down; I would like to detect when I rise the stool and flip it upside down to rest over the table, so to start an automation that would clean also the undertable zone.

1 Like

Smart Vibration Sensor - Wireless Vibration Detector | Aqara

1 Like

A wireless sensor tag might do it. They work quite well for sensing changes in the angle of doors/windows, and they’re pretty small. Battery life is about half what they claim, though.

https://wirelesstag.net/

Are those tags local or cloud?

Cloud. You need a tag manager too ($50).

then it’s no go for me because I would much prefer a local push solution. Also it does not seems to be available in my country. Thanks anyway

Using a Wemos D1 Mini (clone) and the MPU6050 accelerometer/gyroscope sensor in an ESPHome device would work relatively well. The math/trigonometry is the most difficult part in working with the sensor, but I use one for detecting the state/orientation of my garage door: down (vertical), moving (changing), and up (horizontal).

esphome:
  name: garagedoor
  platform: ESP8266
  board: d1_mini

#
# WiFi parameters
#
#    
wifi:
  fast_connect: true
  power_save_mode: NONE
  domain:          .local
  use_address:     garagedoor.local
  reboot_timeout:  5min
  networks:
    ssid:     "redacted"
    password: "redacted"

# Enable logging
logger:
  level: INFO

# Enable Home Assistant API
api:
  password: "redacted"

ota:
  password: "redacted"

    
globals:
  - id: gyro_angle_x
    type: float
    restore_value: no
  - id: gyro_angle_y
    type: float
    restore_value: no
  - id: gyro_angle_z
    type: float
    restore_value: no
        
  - id: delta_accel_x
    type: float
    restore_value: no
  - id: delta_accel_y
    type: float
    restore_value: no
  - id: delta_accel_z
    type: float
    restore_value: no

  - id: delta_gyro_x
    type: float
    restore_value: no
  - id: delta_gyro_y
    type: float
    restore_value: no
  - id: delta_gyro_z
    type: float 
    restore_value: no
    
i2c:
  sda: D3
  scl:  D4
  scan: True
 
sensor:
  - platform: mpu6050
    update_interval: 5.00s
    address: 0x68
    accel_x:
      accuracy_decimals: 1
      name: "Garagedoor Accel X"
      id: garagedoor_accel_x
      internal: false
      filters:
        - lambda: |-
            id(delta_accel_x) = fabsf(id(garagedoor_accel_x).state - x);
            return(x);
    accel_y:
      accuracy_decimals: 1
      name: "Garagedoor Accel Y"
      id: garagedoor_accel_y
      internal: false
      filters:
        - lambda: |-
            id(delta_accel_y) = fabsf(id(garagedoor_accel_y).state - x);
            return(x);
    accel_z:
      accuracy_decimals: 1
      name: "Garagedoor Accel Z"
      id: garagedoor_accel_z
      internal: false
      filters:
        - lambda: |-
            id(delta_accel_z) = fabsf(id(garagedoor_accel_z).state - x);
            return(x);
            
    gyro_x:
      accuracy_decimals: 1
      name: "Garagedoor Gyro X"
      id: garagedoor_gyro_x
      internal: false
      filters:
        - lambda: |-
            id(delta_gyro_x) = fabsf(id(garagedoor_gyro_x).state - x);
            return(x);
    gyro_y:
      accuracy_decimals: 1
      name: "Garagedoor Gyro Y"
      id: garagedoor_gyro_y
      internal: false
      filters:
        - lambda: |-
            id(delta_gyro_y) = fabsf(id(garagedoor_gyro_y).state - x);
            return(x);
    gyro_z:
      accuracy_decimals: 1
      name: "Garagedoor Gyro Z"
      id: garagedoor_gyro_z
      internal: false
      filters:
        - lambda: |-
            id(delta_gyro_z) = fabsf(id(garagedoor_gyro_z).state - x);
            return(x);
  
  - platform: template 
    name: Garagedoor X Angle
    id: garagedoor_X_angle
    accuracy_decimals: 1
    update_interval: 5s
    internal: false
    filters:
      - sliding_window_moving_average:
          window_size:   5
          send_every:    10
          send_first_at: 10
    lambda: |-
        /*
         * Convert gyro values to degrees/second
         */
        double FS_SEL       = 131.000;
        double gyro_x_value = id(garagedoor_gyro_x).state / FS_SEL;
        double gyro_y_value = id(garagedoor_gyro_y).state / FS_SEL;
        double gyro_z_value = id(garagedoor_gyro_z).state / FS_SEL;

        /*
         * Obtain raw acceleration values
         */
        double accel_x = id(garagedoor_accel_x).state;
        double accel_y = id(garagedoor_accel_y).state;
        double accel_z = id(garagedoor_accel_z).state;

        /*
         * Calculate angle values from accelerometer
         */
        // double accel_angle_x = abs(atan(     accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2))) * RAD_TO_DEG);
        // double accel_angle_y = abs(atan(-1 * accel_x/sqrt(pow(accel_y,2) + pow(accel_z,2))) * RAD_TO_DEG);
        double accel_angle_x = abs(atan2(accel_y, accel_z) * RAD_TO_DEG);
        
        /*
         * Round to nearest 0 or 5
         */
        id(gyro_angle_x) = round(accel_angle_x / 5.0) * 5;
        return id(gyro_angle_x);

binary_sensor:  
  - platform: template
    device_class: vibration
    name: "Garagedoor Vibration"
    id: garagedoor_vibration
    lambda: |-
      if (isnan(id(delta_accel_x)) or 
          isnan(id(delta_accel_y)) or 
          isnan(id(delta_accel_z)) or
          isnan(id(delta_gyro_x))  or
          isnan(id(delta_gyro_y))  or 
          isnan(id(delta_gyro_z))) 
      {
        id(garagedoor).publish_state("Idle");
        return {};
      }
      else if (abs(id(delta_accel_x)) > 1.0 or abs(id(delta_accel_y)) > 1.0 or abs(id(delta_accel_z)) > 1.0) 
      {
        return(true);
      } else {
        return(false);
      }
    filters:
    on_press:
      then:
        - text_sensor.template.publish:
            id: garagedoor
            state: Moving
    on_release:
      then:
        - text_sensor.template.publish:
            id: garagedoor
            state: Idle
            
  - platform: template
    device_class: door
    name: "Garagedoor Open"
    id: garagedoor_open_or_closed
    lambda: |-
      if (isnan(id(delta_accel_x)) or 
          isnan(id(delta_accel_y)) or 
          isnan(id(delta_accel_z)) or
          isnan(id(delta_gyro_x))  or
          isnan(id(delta_gyro_y))  or 
          isnan(id(delta_gyro_z))) 
      {
        id(garagedoor_open).publish_state("????");
        return {};
      }
      else if (id(gyro_angle_x) > 87 && id(gyro_angle_x) < 93)
      {
        id(garagedoor_open).publish_state("Closed");
        return(false);
      } else {
        id(garagedoor_open).publish_state("Open");
        return(true);
      }
    filters:
    on_press:
      then:
        - text_sensor.template.publish:
            id: garagedoor_open
            state: Open
    on_release:
      then:
        - text_sensor.template.publish:
            id: garagedoor_open
            state: Closed
      
text_sensor:
  - platform: template
    icon: mdi:garage-variant
    name: Garagedoor_motion
    id: garagedoor
    update_interval: 5s

  - platform: template
    icon: mdi:garage-variant
    name: Garagedoor_Open
    id: garagedoor_open
    update_interval: 5s

But you can’t have ESP-home on a battery powered device.

There are Wemos ESP8266 devices built onto an 18650 battery holder. Using a 3400 mAh lithium-ion battery can provide almost one year of battery life, using deep sleep mode.

Not surprisingly, there are now 9900 mAh 18650 cells available.

I went with your suggestion and get my hand on an aqara vibration sensor.

I have it paired to a sonoff zigbee 3.0 dongle plus and works like a charm. I didn’t even had to install any aqara or sonoff app, no need to create the n-th account for a service that I would have used once. Local solutions are so nice!

1 Like