Yes, it helped me. I assumed that my device it will be powered by external source.
Batteries no needed anymore.
Also I avoided relay; I used transistor as a switch…
Automotive door lock actuator in the tank, pulling on the flush lever.
I’ve finalized this topic…
As I said - batteries are removed, power supply via wall charger.
I added button for manual activation or check if all is working.
The on-board blue LED I used as pre-warning blinking (~3 sec. before spray),
to avoid spray in someone eyes, etc.
Here is the code - if someone has some suggestions - please provide proposal for changes/improvement…
#version: BS08122020
esphome:
name: air_refreshener_bath_small
platform: ESP8266
board: esp07
wifi:
ssid: "My-Wi-Fi"
password: "12345"
# Manual IP
manual_ip:
static_ip: 192.168.1.167
gateway: 192.168.1.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 8.8.4.4
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Air Refreshener Bath Small"
password: "12345"
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
switch:
# manual activation/switch in HA
- platform: gpio
name: "Air Refreshener Bath Small"
pin: GPIO12
id: dc_motor
# on board blue led visual action spray
- platform: gpio
name: "On board Blue LED"
id: onboard_blue_led
pin:
number: GPIO2
mode: OUTPUT
inverted: true
restore_mode: ALWAYS_OFF
- platform: template
id: air_refreshener_single_click_spray_small_bathroom
name: "Air Refreshener Single Click Spray Small Bathroom"
lambda: |-
if (id(dc_motor).state) {
return true;
} else {
return false;
}
turn_on_action:
- switch.turn_on: dc_motor
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: dc_motor
- switch.turn_off: onboard_blue_led
# Define scrip 'spray 2 times with LED blinking'
script:
- id: spray_2_times
mode: restart
then:
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: onboard_blue_led
- delay: 0.5s
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: onboard_blue_led
- delay: 0.5s
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: onboard_blue_led
- switch.turn_on: dc_motor
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: dc_motor
- switch.turn_off: onboard_blue_led
- delay: 15s
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: onboard_blue_led
- delay: 0.5s
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: onboard_blue_led
- delay: 0.5s
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: onboard_blue_led
- switch.turn_on: dc_motor
- switch.turn_on: onboard_blue_led
- delay: 0.5s
- switch.turn_off: dc_motor
- switch.turn_off: onboard_blue_led
binary_sensor:
# Manual button to activate manually spray
# On board blue LED will blik 5 times befor spray
# then dc_motor is activated,
# then 15s break and the same is repeated
- platform: gpio
name: "Air Refreshener Manual Button Spray Small Bathroom"
pin:
number: GPIO14
mode: input_pullup
inverted: true
internal: true
filters:
- delayed_on: 10ms
on_press:
then:
- script.execute: spray_2_times
# Timer part, scheduled for work-days and holiday-days
# WORKING DAYS
time:
# the night cycle, working days, 03:00
- platform: sntp
id: cycle_0_wd_night
on_time:
- seconds: 0
minutes: 00
hours: 3
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the morning cycle, working days, 05:25
- platform: sntp
id: cycle_1_wd_morning
on_time:
- seconds: 0
minutes: 25
hours: 5
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the morning cycle, working days, 06:00
- platform: sntp
id: cycle_2_wd_morning
on_time:
- seconds: 0
minutes: 0
hours: 6
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the morning cycle, working days, 06:15
- platform: sntp
id: cycle_3_wd_morning
on_time:
- seconds: 0
minutes: 15
hours: 6
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the morning cycle, working days, 06:45
- platform: sntp
id: cycle_4_wd_morning
on_time:
- seconds: 0
minutes: 45
hours: 6
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the afternoon cycle, working days, 15:30
- platform: sntp
id: cycle_5_wd_afternoon
on_time:
- seconds: 0
minutes: 30
hours: 15
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the afternoon cycle, working days, 16:00
- platform: sntp
id: cycle_6_wd_afternoon
on_time:
- seconds: 0
minutes: 00
hours: 16
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the evening cycle, working days, 18:30
- platform: sntp
id: cycle_7_wd_evening
on_time:
- seconds: 0
minutes: 30
hours: 18
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the evening cycle, working days, 19:00
- platform: sntp
id: cycle_8_wd_evening
on_time:
- seconds: 0
minutes: 00
hours: 19
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the evening cycle, working days, 20:00
- platform: sntp
id: cycle_9_wd_evening
on_time:
- seconds: 0
minutes: 00
hours: 20
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the evening cycle, working days, 21:00
- platform: sntp
id: cycle_10_wd_evening
on_time:
- seconds: 0
minutes: 00
hours: 21
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# the evening cycle, working days, 22:15
- platform: sntp
id: cycle_11_wd_evening
on_time:
- seconds: 0
minutes: 15
hours: 22
days_of_week: MON-FRI
then:
- script.execute: spray_2_times
# HOLIDAY DAYS
# the night cycle, holiday days, 03:00
- platform: sntp
id: cycle_12_hd_night
on_time:
- seconds: 0
minutes: 00
hours: 3
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the morning cycle, holiday days, 07:25
- platform: sntp
id: cycle_13_hd_morning
on_time:
- seconds: 0
minutes: 25
hours: 7
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the morning cycle, holiday days, 06:00
- platform: sntp
id: cycle_14_hd_morning
on_time:
- seconds: 0
minutes: 0
hours: 6
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the morning cycle, holiday days, 08:30
- platform: sntp
id: cycle_15_hd_morning
on_time:
- seconds: 0
minutes: 30
hours: 8
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the morning cycle, holiday days, 09:15
- platform: sntp
id: cycle_16_hd_morning
on_time:
- seconds: 0
minutes: 15
hours: 9
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the morning cycle, holiday days, 11:15
- platform: sntp
id: cycle_17_hd_morning
on_time:
- seconds: 0
minutes: 15
hours: 11
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the afternoon cycle, holiday days, 14:00
- platform: sntp
id: cycle_18_hd_afternoon
on_time:
- seconds: 0
minutes: 00
hours: 14
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the afternoon cycle, holiday days, 16:00
- platform: sntp
id: cycle_19_hd_afternoon
on_time:
- seconds: 0
minutes: 00
hours: 16
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the evening cycle, holiday days, 18:30
- platform: sntp
id: cycle_20_hd_evening
on_time:
- seconds: 0
minutes: 30
hours: 18
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the evening cycle, holiday days, 19:00
- platform: sntp
id: cycle_21_hd_evening
on_time:
- seconds: 0
minutes: 00
hours: 19
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the evening cycle, holiday days, 20:00
- platform: sntp
id: cycle_22_hd_evening
on_time:
- seconds: 0
minutes: 00
hours: 20
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the evening cycle, holiday days, 21:00
- platform: sntp
id: cycle_23_hd_evening
on_time:
- seconds: 0
minutes: 00
hours: 21
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the evening cycle, holiday days, 22:15
- platform: sntp
id: cycle_24_hd_evening
on_time:
- seconds: 0
minutes: 15
hours: 22
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
# the evening cycle, holiday days, 23:15
- platform: sntp
id: cycle_25_hd_evening
on_time:
- seconds: 0
minutes: 15
hours: 23
days_of_week: SAT-SUN
then:
- script.execute: spray_2_times
#END
Hi there
Could you detail the circuit? I’m interested on achieving the same as you did!
Best regards
HP
The circuit diagram is in 1st post…
There are only 4 electronic components.
R1 is 0,33kOhm.
What other detailed info you want?
My version of the implementation of an air freshener with the determination of the presence of a balloon and the determination of the aroma of the balloon. Watch the video.
Smart air freshener with detection of the presence of the balloon and the aroma of the balloon
The project used an automatic air freshener from the company Glade with replaceable cylinders at 2400 spray, which I redesigned and integrated into the Home Assistant.
What opportunities does the redesigned air freshener provide?
- Spray the balloon with Home Assistant automation tools
- Spray the balloon with a built-in timer
- Sensor pressing the physical button on the air fresheners
- Determines the presence of a balloon
- Determines the aroma of the balloon
- It is possible to keep a record of the consumption of each cylinder or only a single one
- Write your own code for sensor output and air freshener control in ESP Home
- Battery powered
- Mains power
Necessary details
Filling on ESP Wemos mini firmware to control the air freshener
In ESP Home, we create a project to control the air freshener
substitutions:
board_name: Glade Air Freshener
node_name: airfreshener_glade
esphome:
name: ${node_name}
comment: WeMos D1 Mini Air Freshener
esp8266:
board: d1_mini
framework:
version: recommended
restore_from_flash: true #We save the preset settings. After a reboot, the settings are not reset
#Resetting data to the flash drive to reduce the wear of the flash drive
preferences:
flash_write_interval: 1min
#Wi-Fi credentials for connecting the board to the home network
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: on
#If there is no connection with WiFi, then the access point will rise
ap:
ssid: !secret ap_esp_ssid
password: !secret ap_esp_password
#The captive portal dE SP Home component is a backup mechanism in case the connection to the configured Wi-Fi fails.
captive_portal:
#Web server
web_server:
port: 80
#Logging
logger:
#OTA и API
ota:
password: "esphome"
api:
password: "esphome"
#####################################################################################
################################## Sensor###########################################
sensor:
#Wi Fi signal strength sensor
- platform: wifi_signal
name: ${board_name} RSSI WiFi
icon: mdi:wifi
update_interval: 60s
#Hidden sensor uptime in seconds
- platform: uptime
name: ${board_name} Uptime sec
icon: mdi:clock-outline
id: uptime_sensor
internal: False
#Hidden service sensor for pressing the button
- platform: template
name: ${board_name} Click Spray
id: sensor_spray
internal: True
#Resistance sensor for measuring resistance and determining the cylinder
#Component Analog To Digital Sensor
- platform: adc
pin: A0
id: source_sensor
name: ${board_name} ADS
update_interval: 1s
- platform: resistance
id: resistance_sensor
sensor: source_sensor
configuration: DOWNSTREAM
resistor: 5.6kOhm
name: ${board_name} Resistance
on_value:
- if:
condition:
- lambda: |-
return int(x) < 30;
then:
- text_sensor.template.publish:
id: ballon
state: "The balloon is removed"
- if:
condition:
- lambda: |-
return int(x) < 140 and int(x) > 100;
then:
- text_sensor.template.publish:
id: ballon
state: "Peony and juicy berries"
- if:
condition:
- lambda: |-
return int(x) < 190 and int(x) > 160;
then:
- text_sensor.template.publish:
id: ballon
state: "Freshness of the morning"
- if:
condition:
- lambda: |-
return int(x) < 270 and int(x) > 250;
then:
- text_sensor.template.publish:
id: ballon
state: "Freshness of linen"
- if:
condition:
- lambda: |-
return int(x) < 650 and int(x) > 620;
then:
- text_sensor.template.publish:
id: ballon
state: "Ocean Oasis"
- if:
condition:
- lambda: |-
return int(x) > 2000;
then:
- text_sensor.template.publish:
id: ballon
state: "Japanese Garden"
#####################################################################################
################################## Бинарный сенсор ##################################
binary_sensor:
#Hidden service binary sensor for pressing the button, which, when the status changes, turns on/off the switch for spraying
- platform: gpio
pin: GPIO13
name: ${board_name} Spray Button Press
internal: True
id: button_sensor_d7
on_press:
then:
- switch.turn_on: switch_spray
- delay: 5s
- switch.turn_off: switch_spray
#A visible binary sensor for status display, this can be useful in Home Assistant automation
- platform: template
name: ${board_name} Status Spray
icon: mdi:spray
id: switch_state
internal: false
lambda: |-
if (id(switch_spray).state) {
return true;
} else {
return false;
}
#####################################################################################
################################## Switch######################################
#Hidden service switch for spraying
switch:
- platform: gpio
pin: GPIO15
name: ${board_name} Single Click Spray
internal: True
id: switch_spray
icon: mdi:spray
restore_mode: ALWAYS_OFF
on_turn_on:
then:
- number.set:
id: id_counter
value: !lambda |-
return ((id(id_counter).state)+1);
- sensor.template.publish:
id: sensor_spray
state: !lambda return id(switch_spray).state;
- component.update: id_counter
- delay: 10s
- switch.turn_off: switch_spray
- sensor.template.publish:
id: sensor_spray
state: !lambda return id(switch_spray).state;
#####################################################################################
###################################### Counter ######################################
number:
#Spray counter
- platform: template
name: ${board_name} Counter
icon: mdi:counter
id: id_counter
restore_value: true
update_interval: 30s
min_value: 0
max_value: 3000
mode: box #slider/box
step: 1
optimistic: true
#####################################################################################
####################################### Button ######################################
button:
#Reboot
- platform: restart
name: ${board_name} Restart
icon: mdi:restart
#Spray
- platform: template
name: ${board_name} Click Spray
icon: mdi:spray
on_press:
then:
- switch.turn_on: switch_spray
#Reset the counter
- platform: template
name: ${board_name} Reset Counters Spray
icon: mdi:restart
on_press:
then:
- number.set:
id: id_counter
value: 0
#####################################################################################
################################### Text Sensor################################
#Uptime
text_sensor:
- platform: template
name: ${board_name} Ballon
icon: mdi:spray
id: ballon
update_interval: 60s
- platform: wifi_info
ip_address:
name: ${board_name} IP
# ssid:
# name: ${board_name} SSID
# bssid:
# name: ${board_name} BSSID
# mac_address:
# name: ${board_name} Mac
# scan_results:
# name: ${board_name} Latest_Scan_Results
#####################################################################################
####################################### Time #######################################
time:
- platform: sntp
id: sntp_time
timezone: Europe/Moscow
Assembling
We extract the native board and do as in the diagram
Increased native board size for understanding.
- The yellow wire is soldered to the second leg on the right to the chip. This wire is soldered to the esp board, to the contacts D8 GPIO15
- Solder the resistor to 1K, and a green wire to it. Next, solder the wire from the resistor to the esp board, to the contacts D7 GPIO13
- The orange wire is +3.3V and soldered to the esp board, to the contacts +3.3V
- The blue wire is soldered to the esp board, to the GND contacts
- We cut the contact on the track of the textolite coming from the yellow wire. This is necessary so that we can control the dispenser when the timer is off
- We cut the spring with the + contact for the battery compartment and solder the diode (highlighted with a red marker). Why is this necessary? This is necessary to protect the esp board from failure for the reason that if there are batteries in the air freshener and we still connect it to the network, then the chip responsible for voltage conversion will not try to charge the battery and will not get very hot, which can fail. The diode prevents current from flowing in the opposite direction to the battery
- On the esp, we solder wires and a 5.1 kOhm resistor (there are resistors included) or 5.6 kOhm. The resistor is soldered to contacts A0 and GND. Solder two wires from contacts A0 (brown wire in the photo) and to +3.3V (black wire in the photo) and stretch to the very bottom of the cylinder body
- We install a 5.5 mm power socket connector into the housing hole, solder the wires from the connector to the step-down of the GSMIN MP1584EN DC-DC voltage converter, and from the step-down to the esp. On the step-down we set the voltage 2.2-3.3v and check the motor power. If the lever is pressed hard into the limiter and starts to crack, then lower the voltage to 2.2V and it should be so that the lever rests against the limiter and at the same time the motor does not have enough strength to push the lever and could not wear off the gears
- We stretch two wires from contacts A 0 and +3.3V and apply hot glue so that there is a circle in the center and an arc at the back. I filled the wires with conductive glue - there is no need to solder.
Important! Conductive glue does not fit well on the smooth surface of the plastic, it begins to swell and peel off. Be sure to sand or scratch the smooth surface thoroughly, then the conductive glue will lie perfectly
- We print the platform on a 3d printer, install 2 magnets to enhance magnetization, install a resistor in the hole and cover it with conductive glue. The consumption of conductive glue can be different, therefore, if there are several platforms, it is advisable to take several pieces. I took 5 packs. The STL model can be downloaded from here
Hi,
I have made my glade automatic air freshener smart.
The PCB from the post above was not the same as mine.
The decision was to use only the motor of the air freshener and get rid of everything else.
My approach:
- Control the dc motor by ESP8266 with DRV8833 h-bridge and a dc/dc buck converter in between to get 3V.
- Providing a “Spray” button to trigger the air freshener.
The repository is an early state.
Things to do:
- Add Spray counter to ESPHome YAML
- Add internal boolean to avoid a new spray command while moving the motor
- Create automations like:
-
- Spray if toilet was flushed and door opened and closed again (will be handled in Home Assistant)
-
- Time scheduled spraying at Home Assistant
The documentation can be found here:
Very interesting… How do you monitor flushing the toilet? What kind of sensor do you use…?
Currently it is not installed but I think an aqara door and window sensor should to the job.
The sensor will be opened, two reeds installed in parallel instead of one. The magnets will be attached at the toilet button plate.
I do not know how it works at your home, ours look like that:
O.K. You have build-in wall system… In my case all is ceramic and outside (old fashioned type)…
Very interesting. My region only have this version of the Glade and I have search the net to find one post that said it is not possible to quite challenging to to be smart. I used a relay to intercept the power. Where it turns on for a 10 seconds, spray and shut off. Works great, but it still uses the battery.
I would imagine my unit version would still work with your setup since it does have a motor? The little issue I would run into is that the unit is quite small and I will need to mount everything outside.
I think it should be possible.
Not sure which motor is used (could also be 1.5V).
First you should measure the voltage on the motor when spraying.
DRV8833 can operate with 3-10V.
I’ve found the post. The shell is different but the internal looks the same down the the pc board. The post said the motor to be 2.5v.
Hey there,
alternative approach: I’ve hacked an Air Wick Freshmatic. The 3D printed cover houses the ESP, which switches the device on and off by acting as a AA battery. The device releases one spray 15 seconds after the power was connected. Assuming this delay is acceptable to you the electrical solution and further HA automation is rather simple. Works perfectly in two bathrooms for the last two years.
Happy to share details and code.
Very clean setup. For this particular Air Wick model without converting it to smart, how does it activate?
For my model, it spray once motion is detected AND every 30 minutes( something like that) throughout the day whether it detects motion or not. Marketing scheme to make you constantly buy the refills.
This particular model sprays 15 seconds after activated, then every 30min or so. This initial spray is what made this clean setup possible. From Home Assistant I simply turn the device on when no one is in the room and turn it off some time after. If you ignore the 15 seconds you could say I have direct control of it spraying.
Here’s a simplified copy of my rules.
On:
- trigger:
- platform: state
entity_id: binary_sensor.bathroom_door
to: "off"
for:
seconds: 5
condition:
- condition: state
entity_id: light.bathroom
state: "off"
action:
- service: switch.turn_on
entity_id: switch.airwick
Off:
- trigger:
- platform: state
entity_id: light.bathroom
to: "on"
- platform: state
entity_id: switch.airwick
to: "on"
for:
minutes: 30
condition:
- condition: state
entity_id: switch.airwick
state: "on"
action:
- service: switch.turn_off
entity_id: switch.airwick
No magic on the ESP either. It’s running standard Tasmota with one “Switch” GPIO.
Hey Daxi,
This is great, thank you so much for sharing. I’d love to see more pictures of the inside as well as the reassembled Air freshener. For example, where does the USB cable enter the air freshener?
Thank you in advance!
@rodri2566: Project is updated and pictures of the final air freshener added:
- Added spray counter as readonly data
- Added reset button to set spraycounter back to 0
- Changed timings for glade cans (previously worked fine for airwick cans but not glade cans)
- Spraying logic moved to a script
- Avoiding multiple script executions by the button which avoids motor stress.
- Moved ESPHome YAML to its own file
Thank you so much for sharing @Daxi . It’s a very elegant solution, both in terms of hardware as well as software.
Hey Daxi.
Added a lock to your code at the end of 2400 sprays and the presence of a spray in the can.
script:
- id: do_spray
then:
- if:
condition:
lambda: 'return id(spray_counter).state < 2400 ;'
then:
- number.increment: spray_counter
- component.update: spray_counter
- fan.hbridge.brake: spray_motor
- fan.turn_on:
id: spray_motor
speed: 80
direction: forward
- delay: 350ms
- fan.hbridge.brake: spray_motor
- fan.turn_on:
id: spray_motor
speed: 80
direction: reverse
- delay: 200ms
- fan.hbridge.brake: spray_motor
- fan.turn_off:
id: spray_motor
- delay: 500ms
sensor:
- platform: template
name: ${friendly_name} ${friendly_suffix_counter}
icon: mdi:counter
id: spray_counter_template
state_class: measurement
unit_of_measurement: ""
accuracy_decimals: 0
lambda: |-
return id(spray_counter).state;
update_interval: 1s
on_value:
- if:
condition:
- lambda: |-
return id(spray_counter).state <= 2399 ;
then:
- text_sensor.template.publish:
id: ballon
state: "The balloon is ok"
- if:
condition:
- lambda: |-
return id(spray_counter).state >= 2400 ;
then:
- text_sensor.template.publish:
id: ballon
state: "empty balloon"
text_sensor:
- platform: template
name: ${friendly_suffix_button_spray} Ballon
icon: mdi:spray
id: ballon
update_interval: 60s