All your Atomberg devices, in the menu bar.

Fans, purifiers and locks, one click away. Fans answer over your Wi‑Fi first, and the app talks to nobody but Atomberg.

macOS 26 or later · Unofficial, not affiliated with Atomberg

Install

Install with Homebrew, a DMG or from source, then paste your API key and refresh token once.

Homebrew

brew install --cask ashwingopalsamy/tap/atomberg-console

DMG

Download Atomberg-Console-<version>.dmg from the latest release, drag the app to Applications, and verify it first:

shasum -a 256 -c Atomberg-Console-*.dmg.sha256
gh attestation verify Atomberg-Console-*.dmg -R ashwingopalsamy/atomberg-console

The app is not notarised, because that needs a paid Apple Developer membership. macOS asks once: right-click the app and choose Open, or run xattr -dr com.apple.quarantine "/Applications/Atomberg Console.app".

From source

git clone https://github.com/ashwingopalsamy/atomberg-console && cd atomberg-console
scripts/bundle.sh && open "build/Atomberg Console.app"

Needs macOS 26 and Xcode 26 or its Command Line Tools. There are no dependencies to fetch.

First run

  1. In the Atomberg Home app, turn on Developer Mode and copy the API key and refresh token.
  2. Open Atomberg Console and paste both. They are stored in your Keychain and sent only to Atomberg’s API.
  3. Allow Local Network access when macOS asks. That is what makes fans free to control.

Uninstall

Quit with the power button, delete the app, then remove ~/Library/Application Support/ATOMBERG and the Keychain item com.ashwin.ATOMBERG. With Homebrew: brew uninstall --zap --cask atomberg-console.

The 100-call budget

A refresh costs one call, a command to a fan on your Wi-Fi costs none, a cloud command costs one, against 100 calls a day.

Atomberg’s developer API allows 100 calls a day and 5 a second on the free plan. The count includes failed calls, and resets at 00:00 UTC. Atomberg Console spends as few as it can.

Action Calls
Refresh all devices 1 (device_id=all reads every device in one call)
Command to a fan heard on your Wi‑Fi 0
Command to a fan through the cloud 1
Command to a purifier 1
Usage figures (kWh, hours) at most once a day, only when you open a detail screen
Access token about one a day

What it does to stay under

  • A refresh is a single call for every device.
  • The popover refreshes only if its data is over two hours old (six hours when every device is a fan heard locally). Settings → Refresh does it on demand.
  • Background reads stop when only 20 calls are left, which keeps them for your own commands.
  • A slow reply to a command is not followed by a second call to check it.

See what it spent

Every cloud request is one line in ~/Library/Application Support/ATOMBERG/calls.log: time, method, path, purpose, status. Headers, bodies and tokens are never written. Settings shows how many calls are left today.

Local control

The fan and your Mac are not on the same Wi-Fi, or macOS is blocking Local Network access for the app.

for the app. The app hears a fan’s beacon once a second on UDP port 5625; if it hears none, it uses the cloud.

Check, in order

  1. Same network. Put the Mac and the fan on the same SSID and band. A guest network, an IoT network or a second router usually isolates them, and no beacon crosses.
  2. Local Network access. System Settings → Privacy & Security → Local Network → Atomberg Console on. The app re-checks every 15 seconds and when you tap the wifi button.
  3. Router isolation. Turn off AP isolation, client isolation or broadcast filtering for the network.
  4. Firewall. The app must be allowed to receive incoming connections (UDP 5625).
  5. Tap the wifi button. It opens a fresh socket and listens for a few seconds. The glyph says what it found.

What you see

Glyph Meaning
wifi (teal) a fan was heard; commands go over your Wi‑Fi and cost nothing
wifi.exclamationmark listening, but no fan heard
wifi.slash local control is off

Still nothing?

Open an issue and paste the last lines of ~/Library/Application Support/ATOMBERG/calls.log. It contains no secrets.

Privacy

Two destinations, no analytics, credentials only in your Keychain, and three commands to check it yourself.

Atomberg Console talks to two things and nothing else.

To How Why Carries
api.developer.atomberg-iot.com HTTPS read and control your devices your API key, a short-lived token, device ids
your fans on your Wi‑Fi UDP 5625 (listen), 5600 (commands) local control speed, power, light, timer

No analytics. No crash reporting. No update check. No third-party code: Package.swift has no dependencies.

How that is enforced

  • Cloud/NetworkPolicy.swift refuses any URL that is not https://api.developer.atomberg-iot.com, and any UDP address that is not private, link-local, loopback or the broadcast address, on a port other than 5625 or 5600.
  • scripts/check-egress.sh fails CI if a network API shows up outside Cloud/ and LAN/, if a URL literal is not on the allowlist, or if a package is added.
  • Tests/ATOMBERGTests/NetworkPolicyTests.swift pins the policy.
  • The About window links to this repository. That opens your browser; the app itself makes no request.

What is stored, and where

What Where
API key, refresh token, access token macOS Keychain, item com.ashwin.ATOMBERG
Device list and last readings ~/Library/Application Support/ATOMBERG/catalogue.json
Calls used today ~/Library/Application Support/ATOMBERG/quota.json
One line per cloud request (method, path, status) ~/Library/Application Support/ATOMBERG/calls.log

calls.log never contains headers, bodies or tokens (a test checks this).

Check it yourself

# every socket the app has open
lsof -nP -a -p "$(pgrep -x ATOMBERG)" -i

# live bytes per connection
nettop -p "$(pgrep -x ATOMBERG)"

# what it asked the cloud for
tail -f "$HOME/Library/Application Support/ATOMBERG/calls.log"

You should see api.developer.atomberg-iot.com:443 and UDP port 5625, and nothing else. A firewall such as Little Snitch or LuLu will show the same.

FAQ

Short answers to the things people ask first.

Why does a command use a cloud call?

Atomberg allows 100 calls a day. A fan that is heard on your Wi‑Fi is controlled directly and costs none. Otherwise a command is one call.

Why isn’t my fan found locally?

The fan and this Mac must be on the same Wi‑Fi, and Local Network access must be on for this app. Tap the wifi button to look again.

What do Local and Cloud mean?

Local: the command goes over your Wi‑Fi. Cloud: it goes through Atomberg’s servers and counts toward the daily limit.

Where are my credentials?

In your macOS Keychain, nowhere else. They are sent only to Atomberg’s API.

What does it connect to?

api.developer.atomberg-iot.com over HTTPS, and your fans on UDP ports 5625 and 5600. Nothing else. No analytics, no updater.

Why does the Keychain ask for access?

macOS asks when it does not recognise the app. Choose Always Allow once.

How do I reset it?

Settings → Replace Credentials. To remove everything, delete the app and the Keychain item “com.ashwin.ATOMBERG”.

Is this official?

No. It is unofficial and not affiliated with Atomberg. Source-available under PolyForm Noncommercial 1.0.0.

Who makes Atomberg Console?

Ashwin Gopalsamy, an independent developer. The source is on GitHub at ashwingopalsamy/atomberg-console, under the PolyForm Noncommercial License 1.0.0.

Which Atomberg devices does it support?

Whatever your developer account lists: fans (local network and cloud), water purifiers and smart locks (cloud only). Local control over UDP exists for fans only.

Is it free?

Yes, for noncommercial use. It is source-available under the PolyForm Noncommercial License 1.0.0, so commercial use is not allowed.

What do I need to run it?

macOS 26 or later, and an Atomberg account with Developer Mode turned on in the Atomberg Home app to get an API key and refresh token.

How do I uninstall it?

Quit it from the power button, delete Atomberg Console.app, then remove ~/Library/Application Support/ATOMBERG and the Keychain item “com.ashwin.ATOMBERG”. With Homebrew: brew uninstall --zap --cask atomberg-console.