Whole home cold air scent diffuser automation is possible without crappy apps!

Recently, I’ve been on a mission to make my home more hotel like. While staying at a hotel, I noticed the lobby smelled really amazing. I thought, hmmm, I could do that.

I purchased a diffuser from aliexpress, specifically one that works with aroma-link app (bt/wifi). The app is riddled with bugs, so I set up a proxy to capture to the apps API calls. I noticed that when the diffuser gets power, it automatically activates, and diffuses scent. So, I thought I’d just control the on/off function and set the diffuser’s internal settings to diffuse for a specified amount of time (you can do this through the device or app). One small modification i did, was rip out that damn speaker that beeps every time the unit powers on.

Here’s the automation thought process:

Turn set hvac fan to ‘on’ to get air circulating (I have an ecobee)
Delay 20 seconds
Turn on diffuser (installed into hvac air exchanger, these connections are included with unit)
Turn off diffuser after 2 mins (done diffusing) (toggle helper switch)
Delay 3 mins (hvac still circulating diffused air)
Set hvac fan back to ‘auto’ (done)

repeat every XX mins.

I’m currently experimenting with concentrations and time of diffusing, but it’s working great! I’ve created a helper toggle to trigger a node red flow that logs in, sends the proper payloads to aroma-link API directly, and controls my diffuser. I can share more details if anyone is interested, but I’d just like to share that it is possible!

This place is smelling amazing!

9 Likes

@phantom2 This is great! I’m looking to do the same thing. What brand/model of scent diffuser did you purchase? Could you share more info about the helper toggle you created for the aroma-link API?

Thats amazing to hear - I’ve been struggling with the darn aromalink app as well. Would you mind sharing your node red flows to get this working?

I have the Jcloud model that uses the same crappy app and have been dying for this exact type of integration. Mind sharing your code/automation?

BTW, these appear to use the Espressif chipset, which means they can probably be flashed with ESPHome or Tasmota. Beyond my skillset/knowledge as to how to do so, but thought I’d mention it.

I’d also appreciate the share.

@phantom2 could you elaborate little more on how to integrate this thing to HA? I just received mine after seeing this post :slight_smile:

Edit:
Figured it out using a smart plug instead of fiddling with the API

alias: Diffuse
description: ""
trigger:
  - platform: time_pattern
    hours: "1"
condition:
  - condition: time
    after: "09:00:00"
    before: "00:00:00"
    weekday:
      - sat
      - fri
      - thu
      - wed
      - tue
      - mon
      - sun
action:
  - service: switch.turn_on
    data: {}
    target:
      entity_id: switch.fan_mode
  - delay:
      hours: 0
      minutes: 0
      seconds: 20
      milliseconds: 0
  - type: turn_on
    device_id: cf462edb5676a0ec81b171ed91815b07
    entity_id: switch.tasmota_10
    domain: switch
  - delay:
      hours: 0
      minutes: 2
      seconds: 0
      milliseconds: 0
  - type: turn_off
    device_id: cf462edb5676a0ec81b171ed91815b07
    entity_id: switch.tasmota_10
    domain: switch
  - delay:
      hours: 0
      minutes: 3
      seconds: 0
      milliseconds: 0
  - service: switch.turn_off
    data: {}
    target:
      entity_id: switch.fan_mode
mode: single

Amazing! Just bought the same unit. Do you mind sharing the API/config you are using in Home Assistant?

I’m also interested if you’re willing to share!

Would you mind explaining how you got this set up? Did you just plug the diffuser into a smart plug and schedule from there? Any issues with the device turning on and off that much?

Yeah, I programmed the machine so that it would start shooting aroma oil as soon as it turns on from 00:00 to 23:59 for 7 days a week.

Now, on Home Assistant side, whenever the automation gets triggered on time, the smart plug (tasmota plug) to which the diffuser machine is connected, turns on, HVAC fan turns on (I have ecobee thermostat hooked up to link with HA), they both operate for set amount of time (2 minutes in this case), the diffuser turns off first, and after 3 more minutes of getting residual diffuser infused air out from the vent, the HVAC fan turns off.
The cycle repeats every 30 mins from 9 AM to 12 AM midnight.

Oh and no issue with it going on and off so far. It’ll be fine. My only worry is, the cost of diffuser oil. 100ml lasts about 2 weeks and it costs $8 per bottle on Aliexpress.

1 Like

@anon12659957 Looking to get this setup for my home. Did you use the same diffuser as @phantom2? Or which diffuser are you using?

Since OP hasn’t replied, I took it upon myself to figure this out today and migrated from my smart-plug setup. I’m using a nebulizing diffuser that uses the Aroma-Link app.

If anyone wants to automate one of these diffusers, there are a few steps you’ll need to take since you’ll need to get your API key, device ID, and user ID.

Node Red flow is below. You’ll need to open the functions and the HTTP nodes and enter the device + user IDs and your API token.

I used an app called “Packet Capture” on Android (the icon kind of looks like a yellow pencil on a blue background and says “SSL”) to reverse engineer the calls and capture the parameters. To get the params, simply open the app, press the play button symbol with a “1” on it, search for “Aroma-Link” and select it. A toast message will say something about the VPN service running. At that point open Aroma-Link and perform any action. Navigate back to Packet Capture and press the stop button, then click the top entry on your screen. In that entry, select any Aroma-Link line-item and locate the needed info.

Additionally, you’ll need to create three Home Assistant helpers - a “diffuse time” number (how long you want the machine to run), a “wait time” number (how long between diffusions), and an on/off toggle that you can control as desired (i.e. overnight or when you go out) if you want to use my flow as-is.

@lockeman if you haven’t purchased a diffuser yet, I also have the JCloud; although an unbranded version. You can get the same machine far cheaper on Aliexpress and even cheaper from AliBaba. If you’re scenting more than ~1,500 sqft I’d get something more powerful.

[{"id":"d10da6230773aeb8","type":"server-state-changed","z":"fab9ef29.39d25","name":"Diffuse time","server":"95d0e223.bc05a","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_number.diffuse_time","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":350,"y":2920,"wires":[["5876c8c71336edbc","69fe0804dd7f58a8"]]},{"id":"5876c8c71336edbc","type":"function","z":"fab9ef29.39d25","name":"Set diffuse time","func":"var diffTime = parseInt(msg.payload);\nflow.set('diffuseS', diffTime, \"store\");\nvar diffMs = diffTime * 1000;\nflow.set('delayMs', diffMs, \"store\");","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":2920,"wires":[[]]},{"id":"cd8c146de43bed86","type":"comment","z":"fab9ef29.39d25","name":"Set diffuse and wait times","info":"","x":390,"y":2860,"wires":[]},{"id":"4de8a39b228a07f7","type":"server-state-changed","z":"fab9ef29.39d25","name":"Diffuse wait","server":"95d0e223.bc05a","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_number.diffuser_wait","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":350,"y":2980,"wires":[["47f09e32449696ad","69fe0804dd7f58a8"]]},{"id":"47f09e32449696ad","type":"function","z":"fab9ef29.39d25","name":"Set wait time","func":"var waitTime = parseInt(msg.payload);\nflow.set('waitTime', waitTime, \"store\");","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":2980,"wires":[[]]},{"id":"2289681d502da424","type":"link out","z":"fab9ef29.39d25","name":"Diffuser link","mode":"link","links":["8797600f6eeaa51b","15792441b2019c0d"],"x":675,"y":3040,"wires":[]},{"id":"69fe0804dd7f58a8","type":"delay","z":"fab9ef29.39d25","name":"","pauseType":"delay","timeout":"150","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":570,"y":3040,"wires":[["2289681d502da424"]]},{"id":"1a2fd2036f9a3d5d","type":"server-state-changed","z":"fab9ef29.39d25","name":"Diffuser on?","server":"95d0e223.bc05a","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.diffuser","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":370,"y":3380,"wires":[["46e12f2105930680"],["0dfd9265428d659e"]]},{"id":"ea34f6aef72debd2","type":"comment","z":"fab9ef29.39d25","name":"API diffuser control","info":"","x":370,"y":3100,"wires":[]},{"id":"530ceba525d30d14","type":"http request","z":"fab9ef29.39d25","name":"Aroma-link POST","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://www.aroma-link.com/v1/app/data/workSetApp","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"access_token","valueType":"other","valueValue":"TOKEN HERE"}],"x":1090,"y":3240,"wires":[[]]},{"id":"bca8d6a57bf7af1e","type":"function","z":"fab9ef29.39d25","name":"Diffuser command","func":"msg.headers = { \"Content-Type\": \"application/json\", \"Transfer-Encoding\": \"chunked\", \"Connection\": \"keep-alive\", \"access-token\": \"YOUR_TOKEN_HERE\"};\nif (flow.get('waitTime', \"store\") && flow.get('diffuseS', \"store\")){\n    msg.payload = { \"deviceId\": YOUR_ID_HERE, \"userId\": YOUR_ID_HERE, \"week\": [0, 1, 2, 3, 4, 5, 6], \"workTimeList\": [{ \"consistenceLevel\": 1, \"enabled\": 1, \"endTime\": \"23:59\", \"pauseDuration\": flow.get('waitTime', \"store\") * 60, \"startTime\": \"00:00\", \"workDuration\": flow.get('diffuseS', \"store\") }, { \"consistenceLevel\": 1, \"enabled\": 0, \"endTime\": \"00:00\", \"pauseDuration\": 120, \"startTime\": \"00:00\", \"workDuration\": 10 }, { \"consistenceLevel\": 1, \"enabled\": 0, \"endTime\": \"00:00\", \"pauseDuration\": 120, \"startTime\": \"00:00\", \"workDuration\": 10 }, { \"consistenceLevel\": 1, \"enabled\": 0, \"endTime\": \"00:00\", \"pauseDuration\": 120, \"startTime\": \"00:00\", \"workDuration\": 10 }, { \"consistenceLevel\": 1, \"enabled\": 0, \"endTime\": \"00:00\", \"pauseDuration\": 120, \"startTime\": \"00:00\", \"workDuration\": 10 }] };\n}\n\nreturn msg;","outputs":1,"timeout":0,"noerr":2,"initialize":"","finalize":"","libs":[],"x":870,"y":3240,"wires":[["530ceba525d30d14"]]},{"id":"7a086d3e3351b319","type":"api-current-state","z":"fab9ef29.39d25","name":"API diffuser control?","server":"95d0e223.bc05a","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.api_diffuser_control","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":640,"y":3240,"wires":[["bca8d6a57bf7af1e"],[]]},{"id":"cc5d5dda475e9a6c","type":"http request","z":"fab9ef29.39d25","name":"Aroma-link switch","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://www.aroma-link.com/v1/app/data/newSwitch","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"other","keyValue":"access_token","valueType":"other","valueValue":"TOKEN HERE"}],"x":1090,"y":3380,"wires":[[]]},{"id":"0c7499f98ba63480","type":"function","z":"fab9ef29.39d25","name":"Diffuser on","func":"msg.headers = { \"Content-Type\": \"application/x-www-form-urlencoded\", \"Transfer-Encoding\": \"chunked\", \"Connection\": \"keep-alive\", \"access-token\": \"YOUR_TOKEN_HERE\"};\nmsg.payload = \"deviceId=YOUR_ID_HERE&&userId=YOUR_ID_HERE&onOff=1\";\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":3360,"wires":[["cc5d5dda475e9a6c","2fa65de51321e519"]]},{"id":"0dfd9265428d659e","type":"api-current-state","z":"fab9ef29.39d25","name":"API diffuser control?","server":"95d0e223.bc05a","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.api_diffuser_control","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":640,"y":3420,"wires":[["04a857f1c3255105"],[]]},{"id":"46e12f2105930680","type":"api-current-state","z":"fab9ef29.39d25","name":"API diffuser control?","server":"95d0e223.bc05a","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.api_diffuser_control","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":640,"y":3340,"wires":[["0c7499f98ba63480"],[]]},{"id":"2fa65de51321e519","type":"delay","z":"fab9ef29.39d25","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":900,"y":3300,"wires":[["bca8d6a57bf7af1e"]]},{"id":"15792441b2019c0d","type":"link in","z":"fab9ef29.39d25","name":"Diffuser link","links":["61c76889ca25f7af","2289681d502da424"],"x":425,"y":3240,"wires":[["7a086d3e3351b319"]]},{"id":"04a857f1c3255105","type":"function","z":"fab9ef29.39d25","name":"Diffuser off","func":"msg.headers = { \"Content-Type\": \"application/x-www-form-urlencoded\", \"Transfer-Encoding\": \"chunked\", \"Connection\": \"keep-alive\", \"access-token\": \"YOUR_TOKEN_HERE\"};\nmsg.payload = \"deviceId=YOUR_ID_HERE&&userId=YOUR_ID_HERE&onOff=0\";\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":3400,"wires":[["cc5d5dda475e9a6c"]]},{"id":"95d0e223.bc05a","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]
1 Like

Hi, Can you share me your setting and configuration’details.
Thanks

Hello, The app “Packet Capture” is discountinued.
Does some one have the exact procedure from A to Z (from diffuser to HomeAssistant) without any SmartPlug? I am really instrested to have it, I manage many Aroma-link diffusers and the actual APp is a mess. Thanks so much in advance for your great help.

1 Like

The app still exists! https://play.google.com/store/apps/details?id=app.greyshirts.sslcapture&pcampaignid=web_share

I’m very interested in this, but the gf is really picky on the oil she uses, and the one she uses is quite expensive.

What’s the quantity of oil do you people use every month using your ha automations?

Well, I went ahead and ordered the diffuser.
It has been a loooong journey because I took the API route and had no experience with REST APIs and whatnot.
A big thank you to @benblb for taking the time to help me out.

I managed to do something pretty decent I think, with different modes I can customize from the dashboard, and schedulers, automations, presence detection, etc.
This is what my dashboard looks like for now, but it’s still a work in progress.

For the less tech-savvy people who would like to go the API route and don’t know where to start, feel free to comment and I’ll try my best to explain what I did.

Bon travail, Guillaume! J’etais content de vous assister. This looks great - much more built out than what I have :smiley:

1 Like

100% just got one of these that uses the Aroma Link app. Do you mind sharing how you used the API’s?

hey mate, so im getting some packet stuff, i managed to get the access-token, but i cant find the other info, DeviceID and userID?

GET /v1/app/version/ota HTTP/1.1
Host: pc.aroma-link.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.5.0
access_token: XXXXXXXX
version: 406

HTTP/1.1 200 
Server: nginx/1.17.6
Date: Tue, 30 Apr 2024 05:28:47 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Methods: *
Access-Control-Max-Age: 3600
Access-Control-Allow-Credentials: true

602
{"code":200,"msg":"OK","data":[{"id":44,"typeId":112,"typeName":"G-Air_2","version":"V1.0.20231013","fileUrl":"http://pc.aroma-link.com/files/64246db9-d12f-4c63-a96a-f122404974e9.rbl","descCn":"1","descEn":"1","status":1,"createTime":"2024-03-30 13:48:06.0","updateTime":"2024-03-30 15:15:15.0","updateBy":1,"updateByName":"admin"},{"id":42,"typeId":110,"typeName":"OV-3","version":"V1.0.20240323","fileUrl":"http://pc.aroma-link.com/files/b9835dd7-b037-413f-a890-264f684c4a5b.rbl","descCn":"1","descEn":"1","status":1,"createTime":"2024-03-22 14:34:43.0","updateTime":"2024-03-22 14:39:56.0","updateBy":1,"updateByName":"admin"},{"id":40,"typeId":77,"typeName":"SC1250","version":"V1.0.20230701","fileUrl":"http://pc.aroma-link.com/files/4f7f1dd4-c492-4cf0-907c-eb4a5d3783ac.rbl","descCn":"1","descEn":"1","status":1,"createTime":"2024-03-12 15:57:47.0","updateTime":"2024-03-22 14:25:14.0","updateBy":1,"updateByName":"admin"},{"id":30,"typeId":100,"typeName":"SL150_DZ","version":"V2.0.20231012","fileUrl":"http://pc.aroma-link.com/files/5de751b5-75eb-462a-ba39-9b3675cc95db.rbl","descCn":"1","descEn":"1","status":1,"createTime":"2023-07-21 14:50:44.0","updateTime":"2023-08-23 22:27:53.0","updateBy":1,"updateByName":"admin"},{"id":26,"typeId":96,"typeName":"Lamp-Scent_DZ","version":"V2.0.20231012","fileUrl":"http://pc.aroma-link.com/files/bf2d81ef-6814-4c9d-9fbe-65d86c42727f.rbl","descCn":"1","descEn":"1","status":1,"createTime":"2023-06-02 13:53:27.0","updateTime":"2023-08-23 22:25:55.0","updateBy":1,"updateByName":"admin"}]}
0