├── .eslintrc
├── .gitattributes
├── .github
├── dependabot.yml
├── labeler.yml
└── workflows
│ ├── beta-release.yml
│ ├── build.yml
│ ├── changerelease.yml
│ ├── dependabot.yml
│ ├── labeler.yml
│ ├── release-drafter.yml
│ ├── release.yml
│ └── stale.yml
├── .gitignore
├── .npmignore
├── BLE.md
├── CHANGELOG.md
├── LICENSE
├── OpenAPI.md
├── README.md
├── branding
├── Node_x_SwitchBot.svg
├── icon.png
└── switchbot.png
├── docs
├── .nojekyll
├── assets
│ ├── hierarchy.js
│ ├── highlight.css
│ ├── icons.js
│ ├── icons.svg
│ ├── main.js
│ ├── navigation.js
│ ├── search.js
│ └── style.css
├── classes
│ ├── Advertising.html
│ ├── SwitchBotBLE.html
│ ├── SwitchBotOpenAPI.html
│ ├── SwitchbotDevice.html
│ ├── WoBlindTilt.html
│ ├── WoBulb.html
│ ├── WoCeilingLight.html
│ ├── WoContact.html
│ ├── WoCurtain.html
│ ├── WoHand.html
│ ├── WoHub2.html
│ ├── WoHumi.html
│ ├── WoHumi2.html
│ ├── WoIOSensorTH.html
│ ├── WoKeypad.html
│ ├── WoLeak.html
│ ├── WoPlugMiniJP.html
│ ├── WoPlugMiniUS.html
│ ├── WoPresence.html
│ ├── WoRelaySwitch1.html
│ ├── WoRelaySwitch1PM.html
│ ├── WoRemote.html
│ ├── WoSensorTH.html
│ ├── WoSensorTHPlus.html
│ ├── WoSensorTHPro.html
│ ├── WoSensorTHProCO2.html
│ ├── WoSmartLock.html
│ ├── WoSmartLockPro.html
│ └── WoStrip.html
├── enums
│ ├── LogLevel.html
│ ├── SwitchBotBLEModel.html
│ ├── SwitchBotBLEModelFriendlyName.html
│ ├── SwitchBotBLEModelName.html
│ └── SwitchBotModel.html
├── hierarchy.html
├── index.html
├── interfaces
│ ├── AdvertisementData.html
│ ├── Chars.html
│ ├── ErrorObject.html
│ ├── NobleTypes.html
│ ├── Params.html
│ ├── Rule.html
│ ├── ServiceData.html
│ ├── SwitchBotBLEDevice.html
│ ├── WebhookDetail.html
│ ├── ad.html
│ ├── body.html
│ ├── bodyChange.html
│ ├── deleteWebhookResponse.html
│ ├── device.html
│ ├── deviceList.html
│ ├── deviceStatus.html
│ ├── deviceStatusRequest.html
│ ├── deviceWebhook.html
│ ├── deviceWebhookContext.html
│ ├── devices.html
│ ├── infraredRemoteList.html
│ ├── irdevice.html
│ ├── pushResponse.html
│ ├── queryWebhookResponse.html
│ ├── setupWebhookResponse.html
│ ├── switchbot.html
│ ├── updateWebhookResponse.html
│ └── webhookRequest.html
├── media
│ ├── BLE.md
│ └── OpenAPI.md
├── modules.html
└── types
│ ├── MacAddress.html
│ ├── batteryCirculatorFan.html
│ ├── batteryCirculatorFanServiceData.html
│ ├── batteryCirculatorFanStatus.html
│ ├── batteryCirculatorFanWebhookContext.html
│ ├── blindTilt.html
│ ├── blindTiltServiceData.html
│ ├── blindTiltStatus.html
│ ├── blindTiltWebhookContext.html
│ ├── bot.html
│ ├── botServiceData.html
│ ├── botStatus.html
│ ├── botWebhookContext.html
│ ├── ceilingLight.html
│ ├── ceilingLightPro.html
│ ├── ceilingLightProServiceData.html
│ ├── ceilingLightProStatus.html
│ ├── ceilingLightProWebhookContext.html
│ ├── ceilingLightServiceData.html
│ ├── ceilingLightStatus.html
│ ├── ceilingLightWebhookContext.html
│ ├── circulatorFanStatus.html
│ ├── circulatorFanWebhookContext.html
│ ├── colorBulb.html
│ ├── colorBulbServiceData.html
│ ├── colorBulbStatus.html
│ ├── colorBulbWebhookContext.html
│ ├── contactSensor.html
│ ├── contactSensorServiceData.html
│ ├── contactSensorStatus.html
│ ├── contactSensorWebhookContext.html
│ ├── curtain.html
│ ├── curtain3.html
│ ├── curtain3ServiceData.html
│ ├── curtain3WebhookContext.html
│ ├── curtainServiceData.html
│ ├── curtainStatus.html
│ ├── curtainWebhookContext.html
│ ├── floorCleaningRobotS10.html
│ ├── floorCleaningRobotS10Status.html
│ ├── floorCleaningRobotS10WebhookContext.html
│ ├── hub2.html
│ ├── hub2ServiceData.html
│ ├── hub2Status.html
│ ├── hub2WebhookContext.html
│ ├── humidifier.html
│ ├── humidifier2ServiceData.html
│ ├── humidifier2Status.html
│ ├── humidifier2WebhookContext.html
│ ├── humidifierServiceData.html
│ ├── humidifierStatus.html
│ ├── humidifierWebhookContext.html
│ ├── indoorCam.html
│ ├── indoorCameraWebhookContext.html
│ ├── keypad.html
│ ├── keypadDetectorServiceData.html
│ ├── keypadTouch.html
│ ├── keypadTouchWebhookContext.html
│ ├── keypadWebhookContext.html
│ ├── lock.html
│ ├── lockPro.html
│ ├── lockProServiceData.html
│ ├── lockProStatus.html
│ ├── lockProWebhookContext.html
│ ├── lockServiceData.html
│ ├── lockStatus.html
│ ├── lockWebhookContext.html
│ ├── meter.html
│ ├── meterPlus.html
│ ├── meterPlusServiceData.html
│ ├── meterPlusStatus.html
│ ├── meterPlusWebhookContext.html
│ ├── meterPro.html
│ ├── meterProCO2ServiceData.html
│ ├── meterProCO2Status.html
│ ├── meterProCO2WebhookContext.html
│ ├── meterProServiceData.html
│ ├── meterProStatus.html
│ ├── meterProWebhookContext.html
│ ├── meterServiceData.html
│ ├── meterStatus.html
│ ├── meterWebhookContext.html
│ ├── motionSensor.html
│ ├── motionSensorServiceData.html
│ ├── motionSensorStatus.html
│ ├── motionSensorWebhookContext.html
│ ├── onadvertisement.html
│ ├── ondiscover.html
│ ├── outdoorMeter.html
│ ├── outdoorMeterServiceData.html
│ ├── outdoorMeterStatus.html
│ ├── outdoorMeterWebhookContext.html
│ ├── panTiltCamWebhookContext.html
│ ├── pantiltCam.html
│ ├── pantiltCam2k.html
│ ├── plug.html
│ ├── plugMini.html
│ ├── plugMiniJPServiceData.html
│ ├── plugMiniJPWebhookContext.html
│ ├── plugMiniStatus.html
│ ├── plugMiniUSServiceData.html
│ ├── plugMiniUSWebhookContext.html
│ ├── plugStatus.html
│ ├── plugWebhookContext.html
│ ├── relaySwitch1Context.html
│ ├── relaySwitch1PMContext.html
│ ├── relaySwitch1PMServiceData.html
│ ├── relaySwitch1PMStatus.html
│ ├── relaySwitch1ServiceData.html
│ ├── relaySwitch1Status.html
│ ├── remote.html
│ ├── remoteServiceData.html
│ ├── robotVacuumCleanerS1.html
│ ├── robotVacuumCleanerS1Plus.html
│ ├── robotVacuumCleanerS1PlusStatus.html
│ ├── robotVacuumCleanerS1PlusWebhookContext.html
│ ├── robotVacuumCleanerS1Status.html
│ ├── robotVacuumCleanerS1WebhookContext.html
│ ├── robotVacuumCleanerServiceData.html
│ ├── stripLight.html
│ ├── stripLightServiceData.html
│ ├── stripLightStatus.html
│ ├── stripLightWebhookContext.html
│ ├── waterLeakDetector.html
│ ├── waterLeakDetectorServiceData.html
│ ├── waterLeakDetectorStatus.html
│ └── waterLeakDetectorWebhookContext.html
├── eslint.config.js
├── jest.config.js
├── package-lock.json
├── package.json
├── src
├── device.ts
├── index.test.ts
├── index.ts
├── parameter-checker.ts
├── settings.test.ts
├── settings.ts
├── switchbot-ble.ts
├── switchbot-openapi.ts
└── types
│ ├── bledevicestatus.ts
│ ├── devicelist.ts
│ ├── devicepush.ts
│ ├── deviceresponse.ts
│ ├── devicestatus.ts
│ ├── devicewebhookstatus.ts
│ └── irdevicelist.ts
├── tsconfig.json
└── typedoc.json
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "extends": [
4 | "eslint:recommended",
5 | "plugin:@typescript-eslint/eslint-recommended",
6 | "plugin:@typescript-eslint/recommended", // uses the recommended rules from the @typescript-eslint/eslint-plugin
7 | "plugin:jest/recommended" // enables eslint-plugin-jest
8 | ],
9 | "parserOptions": {
10 | "ecmaVersion": 2021,
11 | "sourceType": "module"
12 | },
13 | "ignorePatterns": [
14 | "dist",
15 | "server"
16 | ],
17 | "rules": {
18 | "quotes": [
19 | "warn",
20 | "single"
21 | ],
22 | "indent": [
23 | "warn",
24 | 2,
25 | {
26 | "SwitchCase": 1
27 | }
28 | ],
29 | "linebreak-style": [
30 | "warn",
31 | "unix"
32 | ],
33 | "semi": [
34 | "warn",
35 | "always"
36 | ],
37 | "comma-dangle": [
38 | "warn",
39 | "always-multiline"
40 | ],
41 | "dot-notation": "off",
42 | "eqeqeq": "warn",
43 | "curly": [
44 | "warn",
45 | "all"
46 | ],
47 | "brace-style": [
48 | "warn"
49 | ],
50 | "prefer-arrow-callback": [
51 | "warn"
52 | ],
53 | "max-len": [
54 | "warn",
55 | 150
56 | ], // use the provided log method instead
57 | "no-non-null-assertion": [
58 | "off"
59 | ],
60 | "comma-spacing": [
61 | "error"
62 | ],
63 | "no-multi-spaces": [
64 | "warn",
65 | {
66 | "ignoreEOLComments": true
67 | }
68 | ],
69 | "no-trailing-spaces": [
70 | "warn"
71 | ],
72 | "lines-between-class-members": [
73 | "warn",
74 | "always",
75 | {
76 | "exceptAfterSingleLine": true
77 | }
78 | ],
79 | "@typescript-eslint/explicit-function-return-type": "off",
80 | "@typescript-eslint/no-non-null-assertion": "off",
81 | "@typescript-eslint/explicit-module-boundary-types": "off",
82 | "@typescript-eslint/no-explicit-any": "error"
83 | }
84 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: 'npm' # See documentation for possible values
9 | directory: '/' # Location of package manifests
10 | target-branch: 'beta-*.*.*'
11 | schedule:
12 | interval: 'daily'
13 | - package-ecosystem: 'github-actions' # See documentation for possible values
14 | directory: '/' # Location of package manifests
15 | target-branch: 'beta-*.*.*'
16 | schedule:
17 | interval: 'daily'
18 |
--------------------------------------------------------------------------------
/.github/labeler.yml:
--------------------------------------------------------------------------------
1 | # Add 'branding' label to any changes within 'docs' folder or any subfolders
2 | branding:
3 | - changed-files:
4 | - any-glob-to-any-file: branding/**
5 |
6 | # Add 'docs' label to any change to .md files within the entire repository
7 | docs:
8 | - changed-files:
9 | - any-glob-to-any-file: '**/*.md'
10 |
11 | # Add 'enhancement' label to any change to src files within the source dir EXCEPT for the docs sub-folder
12 | enhancement:
13 | - changed-files:
14 | - any-glob-to-any-file: 'src/**/*'
15 | - any-glob-to-any-file: 'config.schema.json'
16 |
17 | # Add 'dependencies' label to any change to src files within the source dir EXCEPT for the docs sub-folder
18 | dependencies:
19 | - changed-files:
20 | - any-glob-to-any-file: 'package.json'
21 | - any-glob-to-any-file: 'package-lock.json'
22 |
23 | # Add 'beta' label to any PR that is opened against the `beta` branch
24 | beta:
25 | - base-branch: 'beta*'
26 |
27 | # Add 'alpha' label to any PR that is opened against the `alpha` branch
28 | alpha:
29 | - base-branch: 'alpha*'
30 |
31 | # Add 'latest' label to any PR that is opened against the `latest` branch
32 | latest:
33 | - base-branch: 'latest'
34 |
35 | # Add 'workflow' to any changes within 'workflow' folder or any subfolders
36 | workflow:
37 | - changed-files:
38 | - any-glob-to-any-file: .github/**
--------------------------------------------------------------------------------
/.github/workflows/beta-release.yml:
--------------------------------------------------------------------------------
1 | name: Beta Release
2 |
3 | on:
4 | push:
5 | branches: [beta-*.*.*, beta]
6 | workflow_dispatch:
7 |
8 | jobs:
9 | build_and_test:
10 | uses: OpenWonderLabs/.github/.github/workflows/nodejs-build-and-test.yml@latest
11 | with:
12 | enable_coverage: true
13 | secrets:
14 | token: ${{ secrets.GITHUB_TOKEN }}
15 |
16 | lint:
17 | needs: build_and_test
18 | uses: OpenWonderLabs/.github/.github/workflows/eslint.yml@latest
19 |
20 | publish:
21 | needs: lint
22 | if: ${{ github.repository == 'OpenWonderLabs/node-switchbot' }}
23 | permissions:
24 | id-token: write
25 | uses: OpenWonderLabs/.github/.github/workflows/npm-publish-esm.yml@latest
26 | with:
27 | tag: 'beta'
28 | dynamically_adjust_version: true
29 | npm_version_command: 'pre'
30 | pre_id: 'beta'
31 | secrets:
32 | npm_auth_token: ${{ secrets.npm_token }}
33 |
34 | pre-release:
35 | needs: publish
36 | if: ${{ github.repository == 'OpenWonderLabs/node-switchbot' }}
37 | uses: OpenWonderLabs/.github/.github/workflows/pre-release.yml@latest
38 | with:
39 | npm_version: ${{ needs.publish.outputs.NPM_VERSION }}
40 | body: |
41 | **Beta Release**
42 | **Version**: v${{ needs.publish.outputs.NPM_VERSION }}
43 | [How To Test Beta Releases](https://github.com/OpenWonderLabs/homebridge-switchbot/wiki/Beta-Version)
44 |
45 | github-releases-to-discord:
46 | name: Discord Webhooks
47 | needs: [build_and_test,publish]
48 | if: ${{ github.repository == 'OpenWonderLabs/node-switchbot' }}
49 | uses: OpenWonderLabs/.github/.github/workflows/discord-webhooks.yml@latest
50 | with:
51 | title: "Node-SwitchBot Beta Release"
52 | description: |
53 | Version `v${{ needs.publish.outputs.NPM_VERSION }}`
54 | url: "https://github.com/homebridge/camera-utils/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}"
55 | secrets:
56 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_BETA || secrets.DISCORD_WEBHOOK_URL_LATEST }}
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Node Build
2 |
3 | on:
4 | push:
5 | branches: [latest]
6 | pull_request:
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build_and_test:
11 | uses: OpenWonderLabs/.github/.github/workflows/nodejs-build-and-test.yml@latest
12 | with:
13 | enable_coverage: true
14 | secrets:
15 | token: ${{ secrets.GITHUB_TOKEN }}
16 | lint:
17 | needs: build_and_test
18 | uses: OpenWonderLabs/.github/.github/workflows/eslint.yml@latest
19 |
--------------------------------------------------------------------------------
/.github/workflows/changerelease.yml:
--------------------------------------------------------------------------------
1 | name: Changelog to Release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | changerelease:
9 | uses: OpenWonderLabs/.github/.github/workflows/changerelease.yml@latest
10 | secrets:
11 | token: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/dependabot.yml:
--------------------------------------------------------------------------------
1 | name: AutoDependabot
2 |
3 | on:
4 | pull_request:
5 | branches: [beta, latest]
6 | pull_request_target:
7 | branches: [beta, latest]
8 |
9 | jobs:
10 | dependabot:
11 | uses: OpenWonderLabs/.github/.github/workflows/dependabot.yml@latest
12 | secrets:
13 | token: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/labeler.yml:
--------------------------------------------------------------------------------
1 | # This workflow will triage pull requests and apply a label based on the
2 | # paths that are modified in the pull request.
3 | #
4 | # To use this workflow, you will need to set up a .github/labeler.yml
5 | # file with configuration. For more information, see:
6 | # https://github.com/actions/labeler/blob/main/README.md
7 |
8 | name: Labeler
9 |
10 | on: pull_request_target
11 |
12 | jobs:
13 | labeler:
14 | uses: OpenWonderLabs/.github/.github/workflows/labeler.yml@latest
15 | secrets:
16 | token: ${{ secrets.GITHUB_TOKEN }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name: Release Drafter
2 |
3 | on:
4 | push:
5 | branches: [latest]
6 | pull_request: # required for autolabeler
7 | types: [opened, reopened, synchronize]
8 | workflow_dispatch:
9 |
10 | jobs:
11 | release-drafter:
12 | uses: OpenWonderLabs/.github/.github/workflows/release-drafter.yml@latest
13 | secrets:
14 | token: ${{ secrets.GITHUB_TOKEN }}
15 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | build_and_test:
9 | uses: OpenWonderLabs/.github/.github/workflows/nodejs-build-and-test.yml@latest
10 | with:
11 | enable_coverage: true
12 | secrets:
13 | token: ${{ secrets.GITHUB_TOKEN }}
14 |
15 | publish:
16 | needs: build_and_test
17 | if: ${{ github.repository == 'OpenWonderLabs/node-switchbot' }}
18 | permissions:
19 | id-token: write
20 | uses: OpenWonderLabs/.github/.github/workflows/npm-publish-esm.yml@latest
21 | secrets:
22 | npm_auth_token: ${{ secrets.npm_token }}
23 |
24 | github-releases-to-discord:
25 | name: Discord Webhooks
26 | needs: [build_and_test,publish]
27 | if: ${{ github.repository == 'OpenWonderLabs/node-switchbot' }}
28 | uses: OpenWonderLabs/.github/.github/workflows/discord-webhooks.yml@latest
29 | with:
30 | title: "Node-SwitchBot Release"
31 | description: |
32 | Version `v${{ needs.publish.outputs.NPM_VERSION }}`
33 | url: "https://github.com/homebridge/camera-utils/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}"
34 | secrets:
35 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_LATEST }}
36 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: Stale workflow
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: '45 11 * * *'
7 |
8 | jobs:
9 | stale:
10 | uses: OpenWonderLabs/.github/.github/workflows/stale.yml@latest
11 | secrets:
12 | token: ${{ secrets.GITHUB_TOKEN }}
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore compiled code
2 |
3 | dist
4 |
5 | # ------------- Defaults -------------
6 |
7 | # Logs
8 |
9 | logs
10 | _.log
11 | npm-debug.log_
12 | yarn-debug.log*
13 | yarn-error.log*
14 | lerna-debug.log\*
15 |
16 | # Diagnostic reports (https://nodejs.org/api/report.html)
17 |
18 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
19 |
20 | # Runtime data
21 |
22 | pids
23 | _.pid
24 | _.seed
25 | \*.pid.lock
26 |
27 | # Directory for instrumented libs generated by jscoverage/JSCover
28 |
29 | lib-cov
30 |
31 | # Coverage directory used by tools like istanbul
32 |
33 | coverage
34 | \*.lcov
35 |
36 | # nyc test coverage
37 |
38 | .nyc_output
39 |
40 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
41 |
42 | .grunt
43 |
44 | # Bower dependency directory (https://bower.io/)
45 |
46 | bower_components
47 |
48 | # node-waf configuration
49 |
50 | .lock-wscript
51 |
52 | # Compiled binary addons (https://nodejs.org/api/addons.html)
53 |
54 | build/Release
55 |
56 | # Dependency directories
57 |
58 | node_modules/
59 | jspm_packages/
60 |
61 | # Snowpack dependency directory (https://snowpack.dev/)
62 |
63 | web_modules/
64 |
65 | # TypeScript cache
66 |
67 | \*.tsbuildinfo
68 |
69 | # Optional npm cache directory
70 |
71 | .npm
72 |
73 | # Optional eslint cache
74 |
75 | .eslintcache
76 |
77 | # Microbundle cache
78 |
79 | .rpt2_cache/
80 | .rts2_cache_cjs/
81 | .rts2_cache_es/
82 | .rts2_cache_umd/
83 |
84 | # Optional REPL history
85 |
86 | .node_repl_history
87 |
88 | # Output of 'npm pack'
89 |
90 | \*.tgz
91 |
92 | # Yarn Integrity file
93 |
94 | .yarn-integrity
95 |
96 | # dotenv environment variables file
97 |
98 | .env
99 | .env.test
100 |
101 | # parcel-bundler cache (https://parceljs.org/)
102 |
103 | .cache
104 | .parcel-cache
105 |
106 | # Next.js build output
107 |
108 | .next
109 |
110 | # Nuxt.js build / generate output
111 |
112 | .nuxt
113 | dist
114 |
115 | # Gatsby files
116 |
117 | .cache/
118 |
119 | # Comment in the public line in if your project uses Gatsby and not Next.js
120 |
121 | # https://nextjs.org/blog/next-9-1#public-directory-support
122 |
123 | # public
124 |
125 | # vuepress build output
126 |
127 | .vuepress/dist
128 |
129 | # Serverless directories
130 |
131 | .serverless/
132 |
133 | # FuseBox cache
134 |
135 | .fusebox/
136 |
137 | # DynamoDB Local files
138 |
139 | .dynamodb/
140 |
141 | # TernJS port file
142 |
143 | .tern-port
144 |
145 | # Stores VSCode versions used for testing VSCode extensions
146 |
147 | .vscode-test
148 |
149 | # yarn v2
150 |
151 | .yarn/cache
152 | .yarn/unplugged
153 | .yarn/build-state.yml
154 | .pnp.\*
155 |
156 | # others
157 | .DS_Store
158 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Ignore source code
2 |
3 | src
4 |
5 | # ------------- Defaults -------------
6 |
7 | # eslint
8 |
9 | .eslintrc
10 |
11 | # typescript
12 |
13 | tsconfig.json
14 |
15 | # vscode
16 |
17 | .vscode
18 |
19 | # nodemon
20 |
21 | nodemon.json
22 |
23 | # Logs
24 |
25 | logs
26 | _.log
27 | npm-debug.log_
28 | yarn-debug.log*
29 | yarn-error.log*
30 | lerna-debug.log\*
31 |
32 | # Diagnostic reports (https://nodejs.org/api/report.html)
33 |
34 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
35 |
36 | # Runtime data
37 |
38 | pids
39 | _.pid
40 | _.seed
41 | \*.pid.lock
42 |
43 | # Directory for instrumented libs generated by jscoverage/JSCover
44 |
45 | lib-cov
46 |
47 | # Coverage directory used by tools like istanbul
48 |
49 | coverage
50 | \*.lcov
51 |
52 | # nyc test coverage
53 |
54 | .nyc_output
55 |
56 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
57 |
58 | .grunt
59 |
60 | # Bower dependency directory (https://bower.io/)
61 |
62 | bower_components
63 |
64 | # node-waf configuration
65 |
66 | .lock-wscript
67 |
68 | # Compiled binary addons (https://nodejs.org/api/addons.html)
69 |
70 | build/Release
71 |
72 | # Dependency directories
73 |
74 | node_modules/
75 | jspm_packages/
76 |
77 | # Snowpack dependency directory (https://snowpack.dev/)
78 |
79 | web_modules/
80 |
81 | # TypeScript cache
82 |
83 | \*.tsbuildinfo
84 |
85 | # Optional npm cache directory
86 |
87 | .npm
88 |
89 | # Optional eslint cache
90 |
91 | .eslintcache
92 |
93 | # Microbundle cache
94 |
95 | .rpt2_cache/
96 | .rts2_cache_cjs/
97 | .rts2_cache_es/
98 | .rts2_cache_umd/
99 |
100 | # Optional REPL history
101 |
102 | .node_repl_history
103 |
104 | # Output of 'npm pack'
105 |
106 | \*.tgz
107 |
108 | # Yarn Integrity file
109 |
110 | .yarn-integrity
111 |
112 | # dotenv environment variables file
113 |
114 | .env
115 | .env.test
116 |
117 | # parcel-bundler cache (https://parceljs.org/)
118 |
119 | .cache
120 | .parcel-cache
121 |
122 | # Next.js build output
123 |
124 | .next
125 |
126 | # Nuxt.js build / generate output
127 |
128 | .nuxt
129 | dist
130 |
131 | # Gatsby files
132 |
133 | .cache/
134 |
135 | # Comment in the public line in if your project uses Gatsby and not Next.js
136 |
137 | # https://nextjs.org/blog/next-9-1#public-directory-support
138 |
139 | # public
140 |
141 | # vuepress build output
142 |
143 | .vuepress/dist
144 |
145 | # Serverless directories
146 |
147 | .serverless/
148 |
149 | # FuseBox cache
150 |
151 | .fusebox/
152 |
153 | # DynamoDB Local files
154 |
155 | .dynamodb/
156 |
157 | # TernJS port file
158 |
159 | .tern-port
160 |
161 | # Stores VSCode versions used for testing VSCode extensions
162 |
163 | .vscode-test
164 |
165 | # yarn v2
166 |
167 | .yarn/cache
168 | .yarn/unplugged
169 | .yarn/build-state.yml
170 | .pnp.\*
171 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License (ISC)
2 | Copyright (c) 2020 SwitchBot
3 |
4 | Permission to use, copy, modify, and/or distribute this software for any
5 | purpose with or without fee is hereby granted, provided that the above
6 | copyright notice and this permission notice appear in all copies.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 | PERFORMANCE OF THIS SOFTWARE.
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 |
5 | # Node-SwitchBot
6 |
7 | [](https://www.npmjs.com/package/node-switchbot)
8 | [](https://www.npmjs.com/package/node-switchbot)
9 |
10 |
11 |
12 | The `node-switchbot` is a Node.js module that allows you to interact with various SwitchBot devices. You can control your [SwitchBot (Bot)'s](https://www.switch-bot.com/bot) arm, operate your [SwitchBot Curtain](https://www.switch-bot.com/products/switchbot-curtain), and manage your [SwitchBot Lock](https://www.switch-bot.com/products/switchbot-lock). Additionally, you can monitor temperature and humidity using the [SwitchBot Thermometer & Hygrometer (Meter)](https://www.switch-bot.com/meter), and check the status of the [SwitchBot Motion Sensor](https://www.switch-bot.com/products/motion-sensor) and [SwitchBot Contact Sensor](https://www.switch-bot.com/products/contact-sensor).
13 |
14 | This module now supports both Bluetooth Low Energy (BLE) and the SwitchBot OpenAPI, providing more flexibility and options for interacting with your devices.
15 |
16 | Please note that most of this module was developed by referencing the official [BLE API](https://github.com/OpenWonderLabs/SwitchBotAPI-BLE) and [OpenAPI](https://github.com/OpenWonderLabs/SwitchBotAPI) documentation. However, some functionalities were developed through trial and error, so there might be inaccuracies in the information obtained from this module.
17 |
18 | ---
19 |
20 | ## [Installation](https://npmjs.org/node-switchbot)
21 |
22 | To install the `node-switchbot` module within your project, use the following command:
23 |
24 | ```sh
25 | $ npm install --save node-switchbot
26 | ```
27 |
28 | ## [BLE (Bluetooth Low Energy)](BLE.md)
29 |
30 | To see a breakdown of how to use the BLE functionality of this project, visit the [BLE (Bluetooth Low Energy)](BLE.md) documentation.
31 |
32 | ## [OpenAPI](OpenAPI.md)
33 |
34 | To see a breakdown of how to use the OpenAPI functionality of this project, visit the [OpenAPI](OpenAPI.md) documentation.
35 |
36 | ## References
37 |
38 | - [SwitchBot (Official website)](https://www.switch-bot.com/)
39 | - [Facebook @SwitchBotRobot](https://www.facebook.com/SwitchBotRobot/)
40 | - [Twitter @SwitchBot](https://twitter.com/switchbot)
41 |
--------------------------------------------------------------------------------
/branding/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenWonderLabs/node-switchbot/bd44206094127456f2b9ec451fafaeb9a77bd787/branding/icon.png
--------------------------------------------------------------------------------
/branding/switchbot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenWonderLabs/node-switchbot/bd44206094127456f2b9ec451fafaeb9a77bd787/branding/switchbot.png
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false.
--------------------------------------------------------------------------------
/docs/assets/hierarchy.js:
--------------------------------------------------------------------------------
1 | window.hierarchyData = "eJyVlkFP2zAYQP+Lzx8jn53YTo5jB7aBiFYQB8QhTQy1SBzkOJsQ6n+fomg0LhB7p0rty3u2Gyd+Jbbv3UCKOypQAEV+D8Sqh1bVTvdmIMUrocinD1N1ihRk80e7erft3Tf1W9eKAHnSpiEFUglktC0pSN1Ww6CG0yP0y851LYH5Z1IQNzQn07Un8xdA6p1uG6sMKe4Y45BSCRlK4JgBlwkITkGmCeRJBrmUgIlAQGQCkCYMkPIckKUSMKUCMM0pYMYzQM4koJgQwSWgZAxQ5hIw5ynQyUJRyPs9EMaWU73tv7baNNe6dWvTXGCBKe6BpFT6hbHdBuRjuw17M/S9Z0q32jxe6MddYPBLMtzhmPmd3riqDiVmKMIuE98+WldpE7DPUNguOPXs55Vp1tUTEfbK1B/1+bilAe+4pWFvnmRH3k6HvJ2O8Er5zhsccKcjRjxtSU/9/WqjzNDb6/N1/4GLiCATXuSnenmuAv/kzETIacI8+YWqntbVExEj5rknLtvx8VIb/aNc1x+4iAhL5YeRm01c5GYTEUmpv/6lVYMy6++CAxUTyP2N+ku11cv8NsH1yJKMCGU8+zRUXsanysuIGGfyKNb1LrBoMxMhF0e3bdy2+49NJ7j8MFC24xAXmciIkGQfz6S0fWTH9jGZ/JP52P7sKvA09NmIWM5TP9ZV1l30deDJ8oaFE/T4yft2bXjdFmRECMXRwjmrnwOFCYlQC1w+WBr/gEkz/s+sjVP2oarVcNqsHy3fSP94SSUT03lv+nxX3LjKLe7pte6MRtT3+/1fvJagpQ=="
--------------------------------------------------------------------------------
/docs/assets/highlight.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --light-hl-0: #795E26;
3 | --dark-hl-0: #DCDCAA;
4 | --light-hl-1: #000000;
5 | --dark-hl-1: #D4D4D4;
6 | --light-hl-2: #A31515;
7 | --dark-hl-2: #CE9178;
8 | --light-hl-3: #0000FF;
9 | --dark-hl-3: #569CD6;
10 | --light-hl-4: #0070C1;
11 | --dark-hl-4: #4FC1FF;
12 | --light-hl-5: #008000;
13 | --dark-hl-5: #6A9955;
14 | --light-hl-6: #001080;
15 | --dark-hl-6: #9CDCFE;
16 | --light-code-background: #FFFFFF;
17 | --dark-code-background: #1E1E1E;
18 | }
19 |
20 | @media (prefers-color-scheme: light) { :root {
21 | --hl-0: var(--light-hl-0);
22 | --hl-1: var(--light-hl-1);
23 | --hl-2: var(--light-hl-2);
24 | --hl-3: var(--light-hl-3);
25 | --hl-4: var(--light-hl-4);
26 | --hl-5: var(--light-hl-5);
27 | --hl-6: var(--light-hl-6);
28 | --code-background: var(--light-code-background);
29 | } }
30 |
31 | @media (prefers-color-scheme: dark) { :root {
32 | --hl-0: var(--dark-hl-0);
33 | --hl-1: var(--dark-hl-1);
34 | --hl-2: var(--dark-hl-2);
35 | --hl-3: var(--dark-hl-3);
36 | --hl-4: var(--dark-hl-4);
37 | --hl-5: var(--dark-hl-5);
38 | --hl-6: var(--dark-hl-6);
39 | --code-background: var(--dark-code-background);
40 | } }
41 |
42 | :root[data-theme='light'] {
43 | --hl-0: var(--light-hl-0);
44 | --hl-1: var(--light-hl-1);
45 | --hl-2: var(--light-hl-2);
46 | --hl-3: var(--light-hl-3);
47 | --hl-4: var(--light-hl-4);
48 | --hl-5: var(--light-hl-5);
49 | --hl-6: var(--light-hl-6);
50 | --code-background: var(--light-code-background);
51 | }
52 |
53 | :root[data-theme='dark'] {
54 | --hl-0: var(--dark-hl-0);
55 | --hl-1: var(--dark-hl-1);
56 | --hl-2: var(--dark-hl-2);
57 | --hl-3: var(--dark-hl-3);
58 | --hl-4: var(--dark-hl-4);
59 | --hl-5: var(--dark-hl-5);
60 | --hl-6: var(--dark-hl-6);
61 | --code-background: var(--dark-code-background);
62 | }
63 |
64 | .hl-0 { color: var(--hl-0); }
65 | .hl-1 { color: var(--hl-1); }
66 | .hl-2 { color: var(--hl-2); }
67 | .hl-3 { color: var(--hl-3); }
68 | .hl-4 { color: var(--hl-4); }
69 | .hl-5 { color: var(--hl-5); }
70 | .hl-6 { color: var(--hl-6); }
71 | pre, code { background: var(--code-background); }
72 |
--------------------------------------------------------------------------------
/docs/assets/navigation.js:
--------------------------------------------------------------------------------
1 | window.navigationData = "eJylm01z2zYQhv+Lzpk6Vib98M2Wk0lSKdZYdnPo9ACRsIQaBBQQtKvp5L93aEoWSCx2F+xV++6z2BfgF0j9+e/Ey3/85GIyt5u5fJJ68mayE347uZhI01T12fH3n7a+aoOPypSTi19/vHnNXD0rX2yvrL+af1jYMkZEggzWR6ekKfX+q6gkyQ3FGTVYbCYTN4Do/rJ8ks6rWpnNCVFoUdeyPguCfcL5NNVdDAmjNGVt/bV8UoVMgV4FrBHd7KS5XH5GRnVQYLRv9korU94p7WNQECQYjV6D6Y1e45kzqbQym7nabMEBhHGCZI0XBQzpQkR+47xQBszvQnj+J2FKKLn9nchs1lMws1lPqcxKwZmVojMTRStFVP18s5Kmtu7uEwQ4RXHK73K/E6BjXQTPnkvxCOW2v+OZS91sFsqoL0so/xTlUe5XGOV+RVCcrKWBTginGE64lVrsuwP+HKKEcT5puaBYywVFq6wH++oieDa2vnir66ha6qbGKG2cSXIWBTnL5sxuwEOvryBolXB+bgvwIHgNMhmp1oI4QfJO7UBEG8BywzOAMl66B1HI+mx4+E/f/wxc2GUljb8WXoCMSIUh17bcg5Q2QCXOtsJsZDK9C2OQ2Va4Gsx/iWCppdTSy29yvbX28VbWO2tqeCigEkf3b1Z6rPg2BUqeq9ojgDZMQ2BnDjE6feWFbzBGJ+CCbuX3RqJd9XQ09jAjCPCgYKPa+532Z5J4EGLgD85Zd7P+WxYwL4hjGGUenHCy7M7+yWURy1CoQ5boMYgBvtq1lnf7XWKJncIYZCmcqGBAF8KSd029RY/aUICBvjfS7TmnAUiIgW8bDYPaAJa4kq71P3l+DuIYppa+2XEag4Qo+PjMBdOOUbTF4Plv+GgXdhrJMGizKwXvjA4qMfRBei29UBpE9hQY6vlYNX027EvQi6jwXrr9TLmi0cJb91EED2K+PQLPIM2A+fa3X87fTwkuuCzTJdKrlFdtcPFBCkFXIVaN1Fk/XQs9/cc14x2CAxreHUAImPmAhs+Fbe6H2TTCUFhG0m1Mis4uUBbmmc1yy6Z8slyHLOXNUEARC3D/p4MVyb0fnNN7nIlR0dMMSUNmIK3MrQHODCjKJOMzhopzKjFNGukQbU++N3xjMl2hLwCAJItKDH38ub6w2rr+du6BeQywCdiCADR8LuxoP8ymEU7CMpr+suHcbejEzCCYRUIdhXV5/ISzkSSLSjmclJJVhjv2ByK0W5/MfpdIf8fNxyYllnCphGmgismmB5w/3sTKCYNMEqvxvL4ftLVupqUwymxubXu3c/52SAZFo8iwF4h0VBXcJ0YKVXXbeyvVYbfRGyk4D1ligzCLBhp6inAYuF2xgmZWqlQPSkan91OEz8ANg1Q57IR9A0EGkTIzIeRXYNkxyg3KjFwvuFbkOaFM2R6/ohoCXwNsgnQCH2NaSdV4HLzB7XiPwNvbVO619LLw6I1NUsircGebYgszX0IZFNzGpJBXgQPP4+rey8GOo6N3gnAe8AStofeAyWxkQmMFlwkeur0gk4SbDYo4ZKLpzI7T7fJ7pRvN63IhisuydLKOxnWKUIxK+vii+fIjK7P/Qj/Ijt/kIwRkqiANnwtO2iDMpuHTl5Dx6PEBfvydmz+7we5aYFUOG3EyEGQQOW4CQm4FhhkjnMBtyPOAZ8CI7qnWc/tGms7omNFuZq/WK2vgTZ0wlsPBrINlWXTYyEiRwyRsTSqpGtaI8IOdIXgQpmmlqgv7FF9qThGS0fj21ngBXbDCWA4Hme+ELIsOznesyGHi851WUjV2wnilPfCQc4rwGdPoXjeMMTh3nRbvNqUj+brZRCzdbDh57XekUG77Ozf/yxJZd6CITyYcS+i4fHhF96Nc1v2K4UJPxCfzXBjqOPy0A/zu6dHljcsFXwInoIAkh7pcMLivojwysgqSwswK4JxBmhwuc9wjR02PmTvi/pffR0781XcqF+1zICCJ7d73H6JomuplO1y61XkEBTRjuNCjaUo3lp+YJVQ9thZ+1uBljanN73F8f/m9/e++kFWNialKdfuJPfj9zCnCZyCjBEUZZHBWh3E+D5/BlI7iPwsvXfsnouOO8xAcCbKJiMWYNr8OaHhClk3H7SfkcLW//gNYd0n3"
--------------------------------------------------------------------------------
/docs/types/MacAddress.html:
--------------------------------------------------------------------------------
1 | MacAddress | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/batteryCirculatorFan.html:
--------------------------------------------------------------------------------
1 | batteryCirculatorFan | node-switchbotType Alias batteryCirculatorFan
batteryCirculatorFan: device & {}
2 |
--------------------------------------------------------------------------------
/docs/types/bot.html:
--------------------------------------------------------------------------------
1 | bot | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/ceilingLight.html:
--------------------------------------------------------------------------------
1 | ceilingLight | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/ceilingLightPro.html:
--------------------------------------------------------------------------------
1 | ceilingLightPro | node-switchbotType Alias ceilingLightPro
2 |
--------------------------------------------------------------------------------
/docs/types/ceilingLightStatus.html:
--------------------------------------------------------------------------------
1 | ceilingLightStatus | node-switchbotType Alias ceilingLightStatus
ceilingLightStatus: deviceStatus & { brightness: number; colorTemperature: number; power: boolean;}
2 |
--------------------------------------------------------------------------------
/docs/types/colorBulb.html:
--------------------------------------------------------------------------------
1 | colorBulb | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/contactSensor.html:
--------------------------------------------------------------------------------
1 | contactSensor | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/floorCleaningRobotS10.html:
--------------------------------------------------------------------------------
1 | floorCleaningRobotS10 | node-switchbotType Alias floorCleaningRobotS10
floorCleaningRobotS10: device & {}
2 |
--------------------------------------------------------------------------------
/docs/types/hub2.html:
--------------------------------------------------------------------------------
1 | hub2 | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/hub2Status.html:
--------------------------------------------------------------------------------
1 | hub2Status | node-switchbothub2Status: deviceStatus & { humidity: number; lightLevel: number; temperature: number;}
2 |
--------------------------------------------------------------------------------
/docs/types/humidifier.html:
--------------------------------------------------------------------------------
1 | humidifier | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/indoorCam.html:
--------------------------------------------------------------------------------
1 | indoorCam | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/indoorCameraWebhookContext.html:
--------------------------------------------------------------------------------
1 | indoorCameraWebhookContext | node-switchbotType Alias indoorCameraWebhookContext
2 |
--------------------------------------------------------------------------------
/docs/types/keypad.html:
--------------------------------------------------------------------------------
1 | keypad | node-switchbotkeypad: device & { keyList: keyList; lockDeviceId: string; remoteType: string }
2 |
--------------------------------------------------------------------------------
/docs/types/keypadTouch.html:
--------------------------------------------------------------------------------
1 | keypadTouch | node-switchbotkeypadTouch: device & { keyList: keyList; lockDeviceId: string; remoteType: string;}
2 |
--------------------------------------------------------------------------------
/docs/types/meter.html:
--------------------------------------------------------------------------------
1 | meter | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/meterPlus.html:
--------------------------------------------------------------------------------
1 | meterPlus | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/meterPlusStatus.html:
--------------------------------------------------------------------------------
1 | meterPlusStatus | node-switchbotType Alias meterPlusStatus
meterPlusStatus: deviceStatus & { battery: number; humidity: number; temperature: number;}
2 |
--------------------------------------------------------------------------------
/docs/types/meterPro.html:
--------------------------------------------------------------------------------
1 | meterPro | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/meterStatus.html:
--------------------------------------------------------------------------------
1 | meterStatus | node-switchbotmeterStatus: deviceStatus & { battery: number; humidity: number; temperature: number;}
2 |
--------------------------------------------------------------------------------
/docs/types/motionSensor.html:
--------------------------------------------------------------------------------
1 | motionSensor | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/outdoorMeter.html:
--------------------------------------------------------------------------------
1 | outdoorMeter | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/outdoorMeterStatus.html:
--------------------------------------------------------------------------------
1 | outdoorMeterStatus | node-switchbotType Alias outdoorMeterStatus
outdoorMeterStatus: deviceStatus & { battery: number; humidity: number; temperature: number;}
2 |
--------------------------------------------------------------------------------
/docs/types/panTiltCamWebhookContext.html:
--------------------------------------------------------------------------------
1 | panTiltCamWebhookContext | node-switchbotType Alias panTiltCamWebhookContext
2 |
--------------------------------------------------------------------------------
/docs/types/pantiltCam.html:
--------------------------------------------------------------------------------
1 | pantiltCam | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/pantiltCam2k.html:
--------------------------------------------------------------------------------
1 | pantiltCam2k | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/plug.html:
--------------------------------------------------------------------------------
1 | plug | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/plugMini.html:
--------------------------------------------------------------------------------
1 | plugMini | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/plugMiniJPWebhookContext.html:
--------------------------------------------------------------------------------
1 | plugMiniJPWebhookContext | node-switchbotType Alias plugMiniJPWebhookContext
2 |
--------------------------------------------------------------------------------
/docs/types/plugMiniUSWebhookContext.html:
--------------------------------------------------------------------------------
1 | plugMiniUSWebhookContext | node-switchbotType Alias plugMiniUSWebhookContext
2 |
--------------------------------------------------------------------------------
/docs/types/plugStatus.html:
--------------------------------------------------------------------------------
1 | plugStatus | node-switchbotplugStatus: deviceStatus & { power: string; version: string }
2 |
--------------------------------------------------------------------------------
/docs/types/plugWebhookContext.html:
--------------------------------------------------------------------------------
1 | plugWebhookContext | node-switchbotType Alias plugWebhookContext
2 |
--------------------------------------------------------------------------------
/docs/types/relaySwitch1Status.html:
--------------------------------------------------------------------------------
1 | relaySwitch1Status | node-switchbotType Alias relaySwitch1Status
relaySwitch1Status: deviceStatus & { switchStatus: 0 | 1; version: string }
2 |
--------------------------------------------------------------------------------
/docs/types/remote.html:
--------------------------------------------------------------------------------
1 | remote | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/robotVacuumCleanerS1.html:
--------------------------------------------------------------------------------
1 | robotVacuumCleanerS1 | node-switchbotType Alias robotVacuumCleanerS1
robotVacuumCleanerS1: device & {}
2 |
--------------------------------------------------------------------------------
/docs/types/robotVacuumCleanerS1Plus.html:
--------------------------------------------------------------------------------
1 | robotVacuumCleanerS1Plus | node-switchbotType Alias robotVacuumCleanerS1Plus
robotVacuumCleanerS1Plus: device & {}
2 |
--------------------------------------------------------------------------------
/docs/types/stripLight.html:
--------------------------------------------------------------------------------
1 | stripLight | node-switchbot
2 |
--------------------------------------------------------------------------------
/docs/types/stripLightStatus.html:
--------------------------------------------------------------------------------
1 | stripLightStatus | node-switchbotType Alias stripLightStatus
stripLightStatus: deviceStatus & { brightness: number; color: string; power: string;}
2 |
--------------------------------------------------------------------------------
/docs/types/waterLeakDetector.html:
--------------------------------------------------------------------------------
1 | waterLeakDetector | node-switchbotType Alias waterLeakDetector
waterLeakDetector: device & {}
2 |
--------------------------------------------------------------------------------
/docs/types/waterLeakDetectorStatus.html:
--------------------------------------------------------------------------------
1 | waterLeakDetectorStatus | node-switchbotType Alias waterLeakDetectorStatus
waterLeakDetectorStatus: deviceStatus & { battery: number; status: 0 | 1 }
2 |
--------------------------------------------------------------------------------
/docs/types/waterLeakDetectorWebhookContext.html:
--------------------------------------------------------------------------------
1 | waterLeakDetectorWebhookContext | node-switchbotType Alias waterLeakDetectorWebhookContext
2 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import antfu from '@antfu/eslint-config'
2 |
3 | export default antfu(
4 | {
5 | ignores: ['dist', 'docs'],
6 | jsx: false,
7 | typescript: true,
8 | formatters: {
9 | markdown: true,
10 | },
11 | rules: {
12 | 'curly': ['error', 'multi-line'],
13 | 'import/extensions': ['error', 'ignorePackages'],
14 | 'import/order': 0,
15 | 'jsdoc/check-alignment': 'error',
16 | 'jsdoc/check-line-alignment': 'error',
17 | 'perfectionist/sort-exports': 'error',
18 | 'perfectionist/sort-imports': [
19 | 'error',
20 | {
21 | groups: [
22 | 'builtin-type',
23 | 'external-type',
24 | 'internal-type',
25 | ['parent-type', 'sibling-type', 'index-type'],
26 | 'builtin',
27 | 'external',
28 | 'internal',
29 | ['parent', 'sibling', 'index'],
30 | 'object',
31 | 'unknown',
32 | ],
33 | order: 'asc',
34 | type: 'natural',
35 | },
36 | ],
37 | 'perfectionist/sort-named-exports': 'error',
38 | 'perfectionist/sort-named-imports': 'error',
39 | 'sort-imports': 0,
40 | 'style/brace-style': ['error', '1tbs', { allowSingleLine: true }],
41 | 'style/quote-props': ['error', 'consistent-as-needed'],
42 | 'test/no-only-tests': 'error',
43 | 'unicorn/no-useless-spread': 'error',
44 | 'unused-imports/no-unused-vars': ['error', { caughtErrors: 'none' }],
45 | 'no-new': 0, // Disable the no-new rule
46 | 'new-cap': 0, // Disable the new-cap rule
47 | 'no-undef': 0, // Disable the no-undef rule
48 | },
49 | },
50 | )
51 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | export const preset = 'ts-jest';
2 | export const testEnvironment = 'node';
3 | export const testMatch = ['**/?(*.)+(spec|test).[jt]s?(x)'];
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-switchbot",
3 | "type": "module",
4 | "version": "3.5.0",
5 | "description": "The node-switchbot is a Node.js module which allows you to control your Switchbot Devices through Bluetooth (BLE).",
6 | "author": "OpenWonderLabs (https://github.com/OpenWonderLabs)",
7 | "license": "MIT",
8 | "homepage": "https://github.com/OpenWonderLabs/node-switchbot",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/OpenWonderLabs/node-switchbot.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/OpenWonderLabs/node-switchbot/issues"
15 | },
16 | "keywords": [
17 | "switchbot",
18 | "bot",
19 | "meter",
20 | "temperature",
21 | "humidity",
22 | "curtain",
23 | "blind",
24 | "BLE",
25 | "Bluetooth Low Energy",
26 | "Bluetooth smart",
27 | "Bluetooth",
28 | "OpenAPI",
29 | "OpenWonderLabs",
30 | "Switchbot API"
31 | ],
32 | "main": "dist/index.js",
33 | "types": "dist/index.d.ts",
34 | "engines": {
35 | "node": "^20 || ^22"
36 | },
37 | "scripts": {
38 | "check": "npm install && npm outdated",
39 | "lint": "eslint src/**/*.ts",
40 | "lint:fix": "eslint src/**/*.ts --fix",
41 | "watch": "npm run build && npm link && nodemon",
42 | "build": "npm run clean && tsc",
43 | "prepublishOnly": "npm run lint && npm run build && npm run docs && npm run lint-docs",
44 | "postpublish": "npm run clean && npm ci",
45 | "clean": "shx rm -rf ./dist",
46 | "test": "vitest run",
47 | "test:watch": "vitest watch",
48 | "test-coverage": "npm run test -- --coverage",
49 | "docs": "typedoc",
50 | "lint-docs": "typedoc --emit none --treatWarningsAsErrors"
51 | },
52 | "readmeFilename": "README.md",
53 | "dependencies": {
54 | "@stoprocent/noble": "^1.19.1",
55 | "async-mutex": "^0.5.0",
56 | "undici": "7.4.0"
57 | },
58 | "optionalDependencies": {
59 | "@stoprocent/bluetooth-hci-socket": "^1.5.2"
60 | },
61 | "devDependencies": {
62 | "@antfu/eslint-config": "^4.4.0",
63 | "@types/aes-js": "^3.1.4",
64 | "@types/debug": "^4.1.12",
65 | "@types/fs-extra": "^11.0.4",
66 | "@types/mdast": "^4.0.4",
67 | "@types/node": "^22.13.9",
68 | "@types/semver": "^7.5.8",
69 | "@types/source-map-support": "^0.5.10",
70 | "@vitest/coverage-v8": "^3.0.7",
71 | "eslint": "^9.21.0",
72 | "eslint-plugin-format": "^1.0.1",
73 | "nodemon": "^3.1.9",
74 | "shx": "^0.3.4",
75 | "ts-node": "^10.9.2",
76 | "typedoc": "^0.27.9",
77 | "typescript": "^5.8.2",
78 | "vitest": "^3.0.7"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/index.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest'
2 |
3 | import * as index from './index.js'
4 |
5 | describe('index module exports', () => {
6 | it('should export switchbot-ble', () => {
7 | expect(index.SwitchBotBLE).toBeDefined()
8 | })
9 |
10 | it('should export switchbot-openapi', () => {
11 | expect(index.SwitchBotOpenAPI).toBeDefined()
12 | })
13 |
14 | it('should export SwitchbotDevice', () => {
15 | expect(index.SwitchbotDevice).toBeDefined()
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2 | *
3 | * index.ts: Switchbot BLE API registration.
4 | */
5 | export * from './device.js'
6 | export * from './switchbot-ble.js'
7 | export * from './switchbot-openapi.js'
8 | export * from './types/bledevicestatus.js'
9 | export * from './types/devicelist.js'
10 | export * from './types/devicepush.js'
11 | export * from './types/deviceresponse.js'
12 | export * from './types/devicestatus.js'
13 | export * from './types/devicewebhookstatus.js'
14 | export * from './types/irdevicelist.js'
15 |
--------------------------------------------------------------------------------
/src/settings.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest'
2 |
3 | import {
4 | CHAR_UUID_DEVICE,
5 | CHAR_UUID_NOTIFY,
6 | CHAR_UUID_WRITE,
7 | COMMAND_TIMEOUT_MSEC,
8 | READ_TIMEOUT_MSEC,
9 | SERV_UUID_PRIMARY,
10 | urls,
11 | WoSmartLockCommands,
12 | WoSmartLockProCommands,
13 | WRITE_TIMEOUT_MSEC,
14 | } from './settings.js'
15 |
16 | describe('switchBot API Settings', () => {
17 | it('should have correct Devices URL', () => {
18 | expect(urls.devicesURL).toBe('https://api.switch-bot.com/v1.1/devices')
19 | })
20 |
21 | it('should have correct setupWebhook URL', () => {
22 | expect(urls.setupWebhook).toBe('https://api.switch-bot.com/v1.1/webhook/setupWebhook')
23 | })
24 |
25 | it('should have correct queryWebhook URL', () => {
26 | expect(urls.queryWebhook).toBe('https://api.switch-bot.com/v1.1/webhook/queryWebhook')
27 | })
28 |
29 | it('should have correct updateWebhook URL', () => {
30 | expect(urls.updateWebhook).toBe('https://api.switch-bot.com/v1.1/webhook/updateWebhook')
31 | })
32 |
33 | it('should have correct deleteWebhook URL', () => {
34 | expect(urls.deleteWebhook).toBe('https://api.switch-bot.com/v1.1/webhook/deleteWebhook')
35 | })
36 |
37 | it('should have correct BLE API constants', () => {
38 | expect(SERV_UUID_PRIMARY).toBe('cba20d00224d11e69fb80002a5d5c51b')
39 | expect(CHAR_UUID_WRITE).toBe('cba20002224d11e69fb80002a5d5c51b')
40 | expect(CHAR_UUID_NOTIFY).toBe('cba20003224d11e69fb80002a5d5c51b')
41 | expect(CHAR_UUID_DEVICE).toBe('2a00')
42 | })
43 |
44 | it('should have correct timeout constants', () => {
45 | expect(READ_TIMEOUT_MSEC).toBe(3000)
46 | expect(WRITE_TIMEOUT_MSEC).toBe(3000)
47 | expect(COMMAND_TIMEOUT_MSEC).toBe(3000)
48 | })
49 |
50 | it('should have correct WoSmartLockProCommands', () => {
51 | expect(WoSmartLockProCommands.GET_CKIV).toBe('570f2103')
52 | expect(WoSmartLockProCommands.LOCK_INFO).toBe('570f4f8102')
53 | expect(WoSmartLockProCommands.UNLOCK).toBe('570f4e0101000080')
54 | expect(WoSmartLockProCommands.UNLOCK_NO_UNLATCH).toBe('570f4e01010000a0')
55 | expect(WoSmartLockProCommands.LOCK).toBe('570f4e0101000000')
56 | expect(WoSmartLockProCommands.ENABLE_NOTIFICATIONS).toBe('570e01001e00008101')
57 | expect(WoSmartLockProCommands.DISABLE_NOTIFICATIONS).toBe('570e00')
58 | })
59 |
60 | it('should have correct WoSmartLockCommands', () => {
61 | expect(WoSmartLockCommands.GET_CKIV).toBe('570f2103')
62 | expect(WoSmartLockCommands.LOCK_INFO).toBe('570f4f8101')
63 | expect(WoSmartLockCommands.UNLOCK).toBe('570f4e01011080')
64 | expect(WoSmartLockCommands.UNLOCK_NO_UNLATCH).toBe('570f4e010110a0')
65 | expect(WoSmartLockCommands.LOCK).toBe('570f4e01011000')
66 | expect(WoSmartLockCommands.ENABLE_NOTIFICATIONS).toBe('570e01001e00008101')
67 | expect(WoSmartLockCommands.DISABLE_NOTIFICATIONS).toBe('570e00')
68 | })
69 | })
70 |
--------------------------------------------------------------------------------
/src/settings.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Switchbot BLE API registration settings.
3 | *
4 | * © 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
5 | */
6 | let baseURL = 'https://api.switch-bot.com'
7 |
8 | let devicesURL = `${baseURL}/v1.1/devices`
9 | let setupWebhook = `${baseURL}/v1.1/webhook/setupWebhook`
10 | let queryWebhook = `${baseURL}/v1.1/webhook/queryWebhook`
11 | let updateWebhook = `${baseURL}/v1.1/webhook/updateWebhook`
12 | let deleteWebhook = `${baseURL}/v1.1/webhook/deleteWebhook`
13 |
14 | /**
15 | * Updates the base URL for the SwitchBot API endpoints.
16 | * @param {string} newBaseURL - The new base URL to use.
17 | */
18 | export function updateBaseURL(newBaseURL: string): void {
19 | baseURL = newBaseURL
20 | devicesURL = `${baseURL}/v1.1/devices`
21 | setupWebhook = `${baseURL}/v1.1/webhook/setupWebhook`
22 | queryWebhook = `${baseURL}/v1.1/webhook/queryWebhook`
23 | updateWebhook = `${baseURL}/v1.1/webhook/updateWebhook`
24 | deleteWebhook = `${baseURL}/v1.1/webhook/deleteWebhook`
25 | }
26 |
27 | export const urls = {
28 | get baseURL() { return baseURL },
29 | get devicesURL() { return devicesURL },
30 | get setupWebhook() { return setupWebhook },
31 | get queryWebhook() { return queryWebhook },
32 | get updateWebhook() { return updateWebhook },
33 | get deleteWebhook() { return deleteWebhook },
34 | }
35 |
36 | /**
37 | * constants used to access SwitchBot BLE API
38 | */
39 | export const SERV_UUID_PRIMARY = 'cba20d00224d11e69fb80002a5d5c51b'
40 | export const CHAR_UUID_WRITE = 'cba20002224d11e69fb80002a5d5c51b'
41 | export const CHAR_UUID_NOTIFY = 'cba20003224d11e69fb80002a5d5c51b'
42 | export const CHAR_UUID_DEVICE = '2a00'
43 |
44 | export const READ_TIMEOUT_MSEC = 3000
45 | export const WRITE_TIMEOUT_MSEC = 3000
46 | export const COMMAND_TIMEOUT_MSEC = 3000
47 |
48 | export const DEFAULT_DISCOVERY_DURATION = 5000
49 | export const PRIMARY_SERVICE_UUID_LIST = []
50 |
51 | export enum WoSmartLockProCommands {
52 | GET_CKIV = '570f2103',
53 | LOCK_INFO = '570f4f8102',
54 | UNLOCK = '570f4e0101000080',
55 | UNLOCK_NO_UNLATCH = '570f4e01010000a0',
56 | LOCK = '570f4e0101000000',
57 | ENABLE_NOTIFICATIONS = '570e01001e00008101',
58 | DISABLE_NOTIFICATIONS = '570e00',
59 | }
60 |
61 | export enum WoSmartLockCommands {
62 | GET_CKIV = '570f2103',
63 | LOCK_INFO = '570f4f8101',
64 | UNLOCK = '570f4e01011080',
65 | UNLOCK_NO_UNLATCH = '570f4e010110a0',
66 | LOCK = '570f4e01011000',
67 | ENABLE_NOTIFICATIONS = '570e01001e00008101',
68 | DISABLE_NOTIFICATIONS = '570e00',
69 | }
70 |
--------------------------------------------------------------------------------
/src/types/devicelist.ts:
--------------------------------------------------------------------------------
1 | /* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2 | *
3 | * devicelist.ts: @switchbot/homebridge-switchbot platform class.
4 | */
5 | export interface deviceList {
6 | device: device[]
7 | }
8 |
9 | export interface device {
10 | deviceId: string
11 | deviceName: string
12 | deviceType: string
13 | enableCloudService: boolean
14 | hubDeviceId: string
15 | version?: number
16 | }
17 |
18 | export type bot = device & {}
19 |
20 | export type curtain = device & {
21 | curtainDevicesIds: string[]
22 | calibrate: boolean
23 | group: boolean
24 | master: boolean
25 | openDirection: string
26 | }
27 |
28 | export type curtain3 = device & {
29 | curtainDevicesIds: string[]
30 | calibrate: boolean
31 | group: boolean
32 | master: boolean
33 | openDirection?: string
34 | }
35 |
36 | export type hub2 = device & {}
37 |
38 | export type meter = device & {}
39 |
40 | export type meterPlus = device & {}
41 |
42 | export type meterPro = device & {}
43 |
44 | export type outdoorMeter = device & {}
45 |
46 | export type lock = device & {
47 | group: boolean
48 | master: boolean
49 | groupName: string
50 | lockDevicesIds: string[]
51 | }
52 |
53 | export type lockPro = device & {
54 | group: boolean
55 | master: boolean
56 | groupName: string
57 | lockDevicesIds: string[]
58 | }
59 |
60 | export type keypad = device & {
61 | remoteType: string
62 | lockDeviceId: string
63 | keyList: keyList
64 | }
65 |
66 | export type keypadTouch = device & {
67 | remoteType: string
68 | lockDeviceId: string
69 | keyList: keyList
70 | }
71 |
72 | interface keyList {
73 | id: number
74 | name: string
75 | type: string
76 | password: string
77 | iv: string
78 | status: string
79 | createTime: number
80 | }
81 |
82 | export type remote = device & {}
83 |
84 | export type motionSensor = device & {}
85 |
86 | export type contactSensor = device & {}
87 |
88 | export type waterLeakDetector = device & {}
89 |
90 | export type ceilingLight = device & {}
91 |
92 | export type ceilingLightPro = device & {}
93 |
94 | export type plug = device & {}
95 |
96 | export type plugMini = device & {}
97 |
98 | export type stripLight = device & {}
99 |
100 | export type colorBulb = device & {}
101 |
102 | export type robotVacuumCleanerS1 = device & {}
103 |
104 | export type robotVacuumCleanerS1Plus = device & {}
105 |
106 | export type floorCleaningRobotS10 = device & {}
107 |
108 | export type humidifier = device & {}
109 |
110 | export type indoorCam = device & {}
111 |
112 | export type pantiltCam = device & {}
113 |
114 | export type pantiltCam2k = device & {}
115 |
116 | export type blindTilt = device & {
117 | blindTiltDevicesIds: string[]
118 | calibrate: boolean
119 | group: boolean
120 | master: boolean
121 | direction: string
122 | slidePosition: number
123 | }
124 |
125 | export type batteryCirculatorFan = device & {}
126 |
--------------------------------------------------------------------------------
/src/types/devicepush.ts:
--------------------------------------------------------------------------------
1 | /* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2 | *
3 | * pushbody.ts: @switchbot/homebridge-switchbot platform class.
4 | */
5 | export interface bodyChange {
6 | command: string
7 | parameter: string
8 | commandType: string
9 | }
10 |
11 | export interface pushResponse {
12 | statusCode: number
13 | body: {
14 | commandId: string
15 | }
16 | message: string
17 | }
18 |
--------------------------------------------------------------------------------
/src/types/deviceresponse.ts:
--------------------------------------------------------------------------------
1 | /* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2 | *
3 | * deviceresponse.ts: @switchbot/homebridge-switchbot platform class.
4 | */
5 | import type { deviceList } from './devicelist.js'
6 | import type { infraredRemoteList } from './irdevicelist.js'
7 |
8 | // json response from SwitchBot API
9 | export interface devices {
10 | statusCode: number
11 | message: string
12 | body: body
13 | }
14 |
15 | export interface body {
16 | deviceList: deviceList
17 | infraredRemoteList: infraredRemoteList
18 | }
19 |
--------------------------------------------------------------------------------
/src/types/irdevicelist.ts:
--------------------------------------------------------------------------------
1 | /* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2 | *
3 | * irdevicelist.ts: ds7@switchbot/homebridge-switchbot platform class.
4 | */
5 | export interface infraredRemoteList {
6 | device: irdevice[]
7 | }
8 |
9 | export interface irdevice {
10 | deviceId?: string
11 | deviceName: string
12 | remoteType: string
13 | hubDeviceId: string
14 | }
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "lib": [
5 | "DOM",
6 | "ES2022"
7 | ],
8 | "rootDir": "src",
9 | "module": "ES2022",
10 | "moduleResolution": "bundler",
11 | "strict": true,
12 | "noImplicitAny": false,
13 | "declaration": true,
14 | "declarationMap": true,
15 | "outDir": "dist",
16 | "sourceMap": true,
17 | "allowSyntheticDefaultImports": true,
18 | "esModuleInterop": true,
19 | "forceConsistentCasingInFileNames": true
20 | },
21 | "include": [
22 | "src"
23 | ],
24 | "exclude": [
25 | "**/*.spec.ts"
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "out": "docs",
3 | "exclude": ["src/**/*.spec.ts"],
4 | "entryPoints": [
5 | "src/index.ts"
6 | ],
7 | "excludePrivate": true,
8 | "excludeProtected": true,
9 | "excludeExternals": true,
10 | "hideGenerator": true,
11 | "includeVersion": false,
12 | "validation": {
13 | "invalidLink": true,
14 | "notExported": false
15 | },
16 | "inlineTags": ["@link", "@see"]
17 | }
18 |
--------------------------------------------------------------------------------