@coffeerunhobby/mcp-ha-connect 2.2.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +1 -1
- package/README.md +11 -2
- package/dist/omadaClient/client.d.ts +6 -1
- package/dist/omadaClient/client.js +12 -1
- package/dist/omadaClient/client.js.map +1 -1
- package/dist/omadaClient/diagnose.d.ts +68 -0
- package/dist/omadaClient/diagnose.js +164 -0
- package/dist/omadaClient/diagnose.js.map +1 -0
- package/dist/omadaClient/index.d.ts +6 -0
- package/dist/omadaClient/index.js +15 -0
- package/dist/omadaClient/index.js.map +1 -1
- package/dist/omadaClient/macGroups.d.ts +58 -0
- package/dist/omadaClient/macGroups.js +124 -0
- package/dist/omadaClient/macGroups.js.map +1 -0
- package/dist/tools/infra/actions.d.ts +1 -1
- package/dist/tools/infra/actions.js +1 -1
- package/dist/tools/omada/index.js +6 -0
- package/dist/tools/omada/index.js.map +1 -1
- package/dist/tools/omada/macGroups.d.ts +19 -0
- package/dist/tools/omada/macGroups.js +77 -0
- package/dist/tools/omada/macGroups.js.map +1 -0
- package/dist/tools/omada/namespace.js +8 -0
- package/dist/tools/omada/namespace.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
- package/.codex/review-rules.md +0 -16
- package/.dockerignore +0 -8
- package/.gitattributes +0 -30
- package/.github/workflows/ci.yml +0 -193
- package/AGENTS.md +0 -389
- package/Dockerfile +0 -50
- package/docker-compose.yml +0 -23
- package/docs/CHANGELOG.md +0 -341
- package/docs/COVERAGE.md +0 -219
- package/docs/QUICK_START.md +0 -240
- package/eslint.config.js +0 -33
- package/n8n/ai-agent-safety-monitor.json +0 -355
- package/openapi.json +0 -1259
- package/scripts/check-version-sync.mjs +0 -69
- package/scripts/generate-jwt.ts +0 -121
- package/src/config.ts +0 -440
- package/src/haClient/automations.ts +0 -261
- package/src/haClient/calendars.ts +0 -94
- package/src/haClient/config.ts +0 -52
- package/src/haClient/devices.ts +0 -653
- package/src/haClient/entities.ts +0 -128
- package/src/haClient/events.ts +0 -689
- package/src/haClient/history.ts +0 -73
- package/src/haClient/index.ts +0 -336
- package/src/haClient/request.ts +0 -142
- package/src/haClient/services.ts +0 -45
- package/src/haClient/states.ts +0 -60
- package/src/haClient/updates.ts +0 -58
- package/src/haClient/wsCommand.ts +0 -44
- package/src/index.ts +0 -164
- package/src/localAI/index.ts +0 -88
- package/src/localAI/prompts.ts +0 -50
- package/src/localAI/providers/base.ts +0 -120
- package/src/localAI/providers/ollama.ts +0 -78
- package/src/localAI/providers/openai.ts +0 -86
- package/src/localAI/types.ts +0 -67
- package/src/omadaClient/auth.ts +0 -178
- package/src/omadaClient/client.ts +0 -337
- package/src/omadaClient/device.ts +0 -118
- package/src/omadaClient/index.ts +0 -310
- package/src/omadaClient/network.ts +0 -284
- package/src/omadaClient/request.ts +0 -365
- package/src/omadaClient/security.ts +0 -51
- package/src/omadaClient/site.ts +0 -344
- package/src/ownerQuestions/service.ts +0 -536
- package/src/permissions/index.ts +0 -143
- package/src/resources/index.ts +0 -213
- package/src/server/auth.ts +0 -175
- package/src/server/chatFace.ts +0 -789
- package/src/server/chatSlice.ts +0 -57
- package/src/server/common.ts +0 -170
- package/src/server/eventSubscription.ts +0 -343
- package/src/server/http.ts +0 -626
- package/src/server/instructions.ts +0 -97
- package/src/server/rateLimiter.ts +0 -227
- package/src/server/stdio.ts +0 -41
- package/src/server/stream.ts +0 -205
- package/src/tools/ai/analyzeSensors.ts +0 -33
- package/src/tools/ai/index.ts +0 -20
- package/src/tools/common.ts +0 -442
- package/src/tools/homeassistant/askOwner.ts +0 -133
- package/src/tools/homeassistant/automationControls.ts +0 -66
- package/src/tools/homeassistant/calendar.ts +0 -97
- package/src/tools/homeassistant/callService.ts +0 -25
- package/src/tools/homeassistant/controlClimate.ts +0 -68
- package/src/tools/homeassistant/controlCover.ts +0 -48
- package/src/tools/homeassistant/controlFan.ts +0 -44
- package/src/tools/homeassistant/controlLight.ts +0 -38
- package/src/tools/homeassistant/controlMediaPlayer.ts +0 -50
- package/src/tools/homeassistant/createAutomation.ts +0 -35
- package/src/tools/homeassistant/deleteAutomation.ts +0 -24
- package/src/tools/homeassistant/entityAction.ts +0 -35
- package/src/tools/homeassistant/entityGuard.ts +0 -28
- package/src/tools/homeassistant/getAllSensors.ts +0 -46
- package/src/tools/homeassistant/getAutomationTrace.ts +0 -30
- package/src/tools/homeassistant/getDomainSummary.ts +0 -29
- package/src/tools/homeassistant/getEntitiesByDomain.ts +0 -56
- package/src/tools/homeassistant/getHistory.ts +0 -24
- package/src/tools/homeassistant/getState.ts +0 -24
- package/src/tools/homeassistant/getStates.ts +0 -46
- package/src/tools/homeassistant/getVersion.ts +0 -21
- package/src/tools/homeassistant/index.ts +0 -121
- package/src/tools/homeassistant/listAutomations.ts +0 -35
- package/src/tools/homeassistant/listEntities.ts +0 -44
- package/src/tools/homeassistant/listPersons.ts +0 -46
- package/src/tools/homeassistant/sceneAndScript.ts +0 -53
- package/src/tools/homeassistant/searchEntities.ts +0 -58
- package/src/tools/homeassistant/sendNotification.ts +0 -179
- package/src/tools/homeassistant/systemTools.ts +0 -52
- package/src/tools/homeassistant/triggerAutomation.ts +0 -24
- package/src/tools/index.ts +0 -78
- package/src/tools/infra/actions.ts +0 -95
- package/src/tools/infra/index.ts +0 -138
- package/src/tools/omada/blockClient.ts +0 -28
- package/src/tools/omada/cyclePoePort.ts +0 -32
- package/src/tools/omada/deleteClient.ts +0 -27
- package/src/tools/omada/disableClientRateLimit.ts +0 -23
- package/src/tools/omada/getClient.ts +0 -14
- package/src/tools/omada/getDevice.ts +0 -14
- package/src/tools/omada/getFirewallSetting.ts +0 -14
- package/src/tools/omada/getInternetInfo.ts +0 -14
- package/src/tools/omada/getLanNetworkList.ts +0 -14
- package/src/tools/omada/getLanProfileList.ts +0 -14
- package/src/tools/omada/getPortForwardingStatus.ts +0 -26
- package/src/tools/omada/getRateLimitProfiles.ts +0 -14
- package/src/tools/omada/getSiteNtpStatus.ts +0 -14
- package/src/tools/omada/getSsidDetail.ts +0 -22
- package/src/tools/omada/getSsidList.ts +0 -21
- package/src/tools/omada/getSwitchStackDetail.ts +0 -14
- package/src/tools/omada/getThreatList.ts +0 -42
- package/src/tools/omada/getWlanGroupList.ts +0 -14
- package/src/tools/omada/graph.ts +0 -187
- package/src/tools/omada/index.ts +0 -153
- package/src/tools/omada/listBlockedClients.ts +0 -17
- package/src/tools/omada/listClients.ts +0 -14
- package/src/tools/omada/listClientsActivity.ts +0 -25
- package/src/tools/omada/listClientsPastConnections.ts +0 -44
- package/src/tools/omada/listDevices.ts +0 -14
- package/src/tools/omada/listDevicesStats.ts +0 -41
- package/src/tools/omada/listMostActiveClients.ts +0 -14
- package/src/tools/omada/listSites.ts +0 -18
- package/src/tools/omada/namespace.ts +0 -1164
- package/src/tools/omada/searchDevices.ts +0 -20
- package/src/tools/omada/setClientRateLimit.ts +0 -26
- package/src/tools/omada/setClientRateLimitProfile.ts +0 -25
- package/src/tools/omada/setSiteNtpServers.ts +0 -36
- package/src/tools/omada/setSsidEnabled.ts +0 -38
- package/src/tools/omada/unblockClient.ts +0 -26
- package/src/tools/types.ts +0 -11
- package/src/tools/utils/pagination-schema.ts +0 -27
- package/src/types/ai/index.ts +0 -11
- package/src/types/ai/types.ts +0 -67
- package/src/types/homeassistant/automations.ts +0 -43
- package/src/types/homeassistant/calendars.ts +0 -26
- package/src/types/homeassistant/config.ts +0 -14
- package/src/types/homeassistant/entities.ts +0 -14
- package/src/types/homeassistant/errors.ts +0 -33
- package/src/types/homeassistant/haConfig.ts +0 -7
- package/src/types/homeassistant/history.ts +0 -13
- package/src/types/homeassistant/index.ts +0 -46
- package/src/types/homeassistant/request.ts +0 -6
- package/src/types/homeassistant/serviceCall.ts +0 -18
- package/src/types/homeassistant/states.ts +0 -58
- package/src/types/homeassistant/updates.ts +0 -28
- package/src/types/index.ts +0 -12
- package/src/types/omada/activeClientInfo.ts +0 -17
- package/src/types/omada/clientActivity.ts +0 -32
- package/src/types/omada/clientBlockStatus.ts +0 -11
- package/src/types/omada/clientPastConnection.ts +0 -82
- package/src/types/omada/index.ts +0 -14
- package/src/types/omada/omadaApiResponse.ts +0 -5
- package/src/types/omada/omadaClientInfo.ts +0 -11
- package/src/types/omada/omadaDeviceInfo.ts +0 -11
- package/src/types/omada/omadaDeviceStats.ts +0 -31
- package/src/types/omada/omadaSiteSummary.ts +0 -5
- package/src/types/omada/oswStackDetail.ts +0 -11
- package/src/types/omada/paginatedResult.ts +0 -6
- package/src/types/omada/rateLimitProfile.ts +0 -58
- package/src/types/omada/threatInfo.ts +0 -38
- package/src/types/omada/tokenResult.ts +0 -6
- package/src/types.ts +0 -2
- package/src/utils/config-validations.ts +0 -68
- package/src/utils/jwt.ts +0 -112
- package/src/utils/logger.ts +0 -121
- package/src/utils/plainText.ts +0 -48
- package/src/utils/redact.ts +0 -59
- package/src/utils/sanitizeError.ts +0 -18
- package/src/utils/tlsDispatcher.ts +0 -69
- package/src/version.ts +0 -5
- package/tests/bdd/automation-creation.spec.ts +0 -214
- package/tests/bdd/automation-management.spec.ts +0 -267
- package/tests/bdd/calendar.spec.ts +0 -190
- package/tests/bdd/configuration.spec.ts +0 -283
- package/tests/bdd/device-control.spec.ts +0 -344
- package/tests/bdd/entity-listing.spec.ts +0 -208
- package/tests/bdd/entity-search.spec.ts +0 -183
- package/tests/bdd/history-retrieval.spec.ts +0 -195
- package/tests/bdd/notifications.spec.ts +0 -238
- package/tests/bdd/service-calls.spec.ts +0 -144
- package/tests/bdd/state-retrieval.spec.ts +0 -204
- package/tests/bench/hotpaths.bench.ts +0 -68
- package/tests/config.test.ts +0 -355
- package/tests/features/automation-creation.feature +0 -36
- package/tests/features/automation-management.feature +0 -54
- package/tests/features/calendar.feature +0 -37
- package/tests/features/configuration.feature +0 -70
- package/tests/features/device-control.feature +0 -100
- package/tests/features/entity-listing.feature +0 -51
- package/tests/features/entity-search.feature +0 -44
- package/tests/features/history-retrieval.feature +0 -38
- package/tests/features/notifications.feature +0 -37
- package/tests/features/service-calls.feature +0 -35
- package/tests/features/state-retrieval.feature +0 -37
- package/tests/fixtures/openapi-default-slice.json +0 -290
- package/tests/haClient/automationTrace.test.ts +0 -59
- package/tests/haClient/automations.test.ts +0 -149
- package/tests/haClient/config.test.ts +0 -117
- package/tests/haClient/entities.test.ts +0 -188
- package/tests/haClient/events.test.ts +0 -455
- package/tests/haClient/eventsTls.test.ts +0 -52
- package/tests/haClient/history.test.ts +0 -228
- package/tests/haClient/index.test.ts +0 -243
- package/tests/haClient/request.test.ts +0 -217
- package/tests/haClient/services.test.ts +0 -120
- package/tests/haClient/states.test.ts +0 -119
- package/tests/haClient/updates.test.ts +0 -193
- package/tests/index.test.ts +0 -160
- package/tests/integration/homeassistant.test.ts +0 -144
- package/tests/integration/omada.test.ts +0 -167
- package/tests/integration/server.test.ts +0 -151
- package/tests/localAI/index.test.ts +0 -177
- package/tests/localAI/ollama.test.ts +0 -187
- package/tests/localAI/openai.test.ts +0 -257
- package/tests/omadaClient/actions.test.ts +0 -161
- package/tests/omadaClient/clientBlocks.test.ts +0 -170
- package/tests/omadaClient/ntp.test.ts +0 -381
- package/tests/omadaClient/site.test.ts +0 -37
- package/tests/ownerQuestions/service.test.ts +0 -499
- package/tests/ownerQuestions/tools.test.ts +0 -186
- package/tests/permissions/index.test.ts +0 -217
- package/tests/resources/index.test.ts +0 -288
- package/tests/scripts/generateJwt.test.ts +0 -44
- package/tests/security/accessControl.test.ts +0 -223
- package/tests/security/authentication.test.ts +0 -117
- package/tests/security/configuration.test.ts +0 -170
- package/tests/security/cryptoTransport.test.ts +0 -172
- package/tests/security/dependencies.test.ts +0 -152
- package/tests/security/injection.test.ts +0 -117
- package/tests/security/insecureDesign.test.ts +0 -121
- package/tests/security/logging.test.ts +0 -131
- package/tests/security/resourceConsumption.test.ts +0 -142
- package/tests/server/auth.test.ts +0 -249
- package/tests/server/chatFace.test.ts +0 -320
- package/tests/server/common.test.ts +0 -84
- package/tests/server/http.test.ts +0 -561
- package/tests/server/instructions.test.ts +0 -152
- package/tests/server/memoizeJsonSchema.test.ts +0 -71
- package/tests/server/stdio.test.ts +0 -99
- package/tests/server/stream.test.ts +0 -285
- package/tests/server/toolVisibility.http.test.ts +0 -111
- package/tests/server/toolVisibility.test.ts +0 -129
- package/tests/tools/ai/analyzeSensors.test.ts +0 -227
- package/tests/tools/common.test.ts +0 -123
- package/tests/tools/homeassistant/handlers.test.ts +0 -872
- package/tests/tools/infra/invokeAction.test.ts +0 -280
- package/tests/tools/omada/graph.test.ts +0 -385
- package/tests/tools/omada/handlers.test.ts +0 -897
- package/tests/tools/omada/namespace.test.ts +0 -483
- package/tests/tools/registry.test.ts +0 -168
- package/tests/utils/config-validations.test.ts +0 -352
- package/tests/utils/jwt.test.ts +0 -115
- package/tests/utils/logger.test.ts +0 -327
- package/tests/utils/redact.test.ts +0 -105
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -38
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
Feature: Entity Listing
|
|
2
|
-
As a Home Assistant user
|
|
3
|
-
I want to list and filter entities
|
|
4
|
-
So that I can get an overview of my smart home devices
|
|
5
|
-
|
|
6
|
-
Scenario: List all entities without filters
|
|
7
|
-
Given a Home Assistant instance with multiple entities
|
|
8
|
-
When I list all entities
|
|
9
|
-
Then I should get all 4 entities
|
|
10
|
-
|
|
11
|
-
Scenario: Filter entities by domain
|
|
12
|
-
Given a Home Assistant instance with multiple entities
|
|
13
|
-
When I list entities filtered by domain "light"
|
|
14
|
-
Then I should only get light entities
|
|
15
|
-
And the count should be 2
|
|
16
|
-
|
|
17
|
-
Scenario: Filter entities by state
|
|
18
|
-
Given a Home Assistant instance with multiple entities
|
|
19
|
-
When I list entities filtered by state "on"
|
|
20
|
-
Then I should only get entities that are "on"
|
|
21
|
-
And the count should be 2
|
|
22
|
-
|
|
23
|
-
Scenario: Filter entities by search query
|
|
24
|
-
Given a Home Assistant instance with multiple entities
|
|
25
|
-
When I list entities filtered by search "room"
|
|
26
|
-
Then I should only get entities matching "room"
|
|
27
|
-
And the count should be 2
|
|
28
|
-
|
|
29
|
-
Scenario: Apply limit to entity list
|
|
30
|
-
Given a Home Assistant instance with multiple entities
|
|
31
|
-
When I list entities with limit 2
|
|
32
|
-
Then I should get at most 2 entities
|
|
33
|
-
|
|
34
|
-
Scenario: Combine multiple filters
|
|
35
|
-
Given a Home Assistant instance with multiple entities
|
|
36
|
-
When I list entities filtered by domain "light" and state "on"
|
|
37
|
-
Then I should only get lights that are on
|
|
38
|
-
And the count should be 1
|
|
39
|
-
|
|
40
|
-
Scenario: Get domain summary
|
|
41
|
-
Given a Home Assistant instance with multiple entities
|
|
42
|
-
When I get the summary for domain "light"
|
|
43
|
-
Then the summary should show domain "light"
|
|
44
|
-
And the total count should be 2
|
|
45
|
-
And the state breakdown should show 1 "on" and 1 "off"
|
|
46
|
-
|
|
47
|
-
Scenario: Get domain summary for non-existent domain
|
|
48
|
-
Given a Home Assistant instance with multiple entities
|
|
49
|
-
When I get the summary for domain "vacuum"
|
|
50
|
-
Then the summary should show domain "vacuum"
|
|
51
|
-
And the total count should be 0
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
Feature: Entity Search
|
|
2
|
-
As a Home Assistant user
|
|
3
|
-
I want to search for entities by name or ID
|
|
4
|
-
So that I can find and control my devices
|
|
5
|
-
|
|
6
|
-
Scenario: Search entities by friendly name
|
|
7
|
-
Given a Home Assistant instance with multiple entities
|
|
8
|
-
When I search for "living"
|
|
9
|
-
Then I should find entities with "living" in their friendly name
|
|
10
|
-
And the results should include "light.living_room"
|
|
11
|
-
|
|
12
|
-
Scenario: Search entities by entity ID
|
|
13
|
-
Given a Home Assistant instance with multiple entities
|
|
14
|
-
When I search for "kitchen"
|
|
15
|
-
Then I should find entities with "kitchen" in their entity ID
|
|
16
|
-
And the results should include "switch.kitchen"
|
|
17
|
-
|
|
18
|
-
Scenario: Search is case insensitive
|
|
19
|
-
Given a Home Assistant instance with multiple entities
|
|
20
|
-
When I search for "BEDROOM"
|
|
21
|
-
Then I should find entities matching "bedroom"
|
|
22
|
-
And the results should include "light.bedroom"
|
|
23
|
-
|
|
24
|
-
Scenario: Search returns multiple matches
|
|
25
|
-
Given a Home Assistant instance with multiple entities
|
|
26
|
-
When I search for "light"
|
|
27
|
-
Then I should find all entities containing "light"
|
|
28
|
-
And the result count should be 2
|
|
29
|
-
|
|
30
|
-
Scenario: Search returns empty for no matches
|
|
31
|
-
Given a Home Assistant instance with multiple entities
|
|
32
|
-
When I search for "nonexistent"
|
|
33
|
-
Then I should find no entities
|
|
34
|
-
|
|
35
|
-
Scenario: Get entities by domain
|
|
36
|
-
Given a Home Assistant instance with multiple entities
|
|
37
|
-
When I get entities for domain "light"
|
|
38
|
-
Then I should only get light entities
|
|
39
|
-
And all entity IDs should start with "light."
|
|
40
|
-
|
|
41
|
-
Scenario: Get entities for empty domain
|
|
42
|
-
Given a Home Assistant instance with multiple entities
|
|
43
|
-
When I get entities for domain "climate"
|
|
44
|
-
Then I should find no entities
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
Feature: History Retrieval
|
|
2
|
-
As a Home Assistant user
|
|
3
|
-
I want to retrieve historical data for my entities
|
|
4
|
-
So that I can analyze trends and patterns
|
|
5
|
-
|
|
6
|
-
Scenario: Get entity history for last 24 hours
|
|
7
|
-
Given an entity "sensor.temperature" with historical data
|
|
8
|
-
When I get the history for the last 24 hours
|
|
9
|
-
Then I should receive historical state changes
|
|
10
|
-
And the history API should be called with the correct time range
|
|
11
|
-
|
|
12
|
-
Scenario: Get entity history with custom time range
|
|
13
|
-
Given an entity "sensor.temperature" with historical data
|
|
14
|
-
When I get the history for the last 48 hours
|
|
15
|
-
Then I should receive historical state changes
|
|
16
|
-
And the time range should be 48 hours
|
|
17
|
-
|
|
18
|
-
Scenario: Get empty history for entity
|
|
19
|
-
Given an entity with no history
|
|
20
|
-
When I get the history
|
|
21
|
-
Then I should receive an empty history array
|
|
22
|
-
|
|
23
|
-
Scenario: Get system log entries
|
|
24
|
-
Given a Home Assistant system log
|
|
25
|
-
When I get the system log
|
|
26
|
-
Then I should receive logbook entries
|
|
27
|
-
And each entry should have timestamp and entity information
|
|
28
|
-
|
|
29
|
-
Scenario: Get system log filtered by entity
|
|
30
|
-
Given a Home Assistant system log
|
|
31
|
-
When I get the system log for entity "light.living_room"
|
|
32
|
-
Then I should receive only entries for that entity
|
|
33
|
-
And the entity filter should be applied
|
|
34
|
-
|
|
35
|
-
Scenario: Get system log with custom time range
|
|
36
|
-
Given a Home Assistant system log
|
|
37
|
-
When I get the system log for the last 48 hours
|
|
38
|
-
Then the logbook API should use the 48 hour time range
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
Feature: Send Notifications
|
|
2
|
-
As a Home Assistant user
|
|
3
|
-
I want to send notifications to my mobile devices
|
|
4
|
-
So that I can be alerted about important events
|
|
5
|
-
|
|
6
|
-
Scenario: Send a simple notification
|
|
7
|
-
Given a notification message "Hello from MCP!"
|
|
8
|
-
When I send the notification to "mobile_app_samsung_s25_fe"
|
|
9
|
-
Then the notification should be sent successfully
|
|
10
|
-
And the service called should be "notify.mobile_app_samsung_s25_fe"
|
|
11
|
-
|
|
12
|
-
Scenario: Send notification with title
|
|
13
|
-
Given a notification message "Motion detected in garage"
|
|
14
|
-
And a notification title "Security Alert"
|
|
15
|
-
When I send the notification to "mobile_app_samsung_s25_fe"
|
|
16
|
-
Then the notification should be sent successfully
|
|
17
|
-
And the title should be included in the service data
|
|
18
|
-
|
|
19
|
-
Scenario: Send notification with action buttons
|
|
20
|
-
Given a notification message "Someone is at the door"
|
|
21
|
-
And an action button "OPEN" with title "Open Door"
|
|
22
|
-
And an action button "IGNORE" with title "Ignore"
|
|
23
|
-
When I send the notification to "mobile_app_samsung_s25_fe"
|
|
24
|
-
Then the notification should be sent successfully
|
|
25
|
-
And the notification data should contain 2 actions
|
|
26
|
-
|
|
27
|
-
Scenario: Send persistent notification (no target)
|
|
28
|
-
Given a notification message "System update available"
|
|
29
|
-
When I send the notification without a target
|
|
30
|
-
Then the notification should be sent to "persistent_notification"
|
|
31
|
-
|
|
32
|
-
Scenario: Send high priority notification
|
|
33
|
-
Given a notification message "Water leak detected!"
|
|
34
|
-
And priority set to "high"
|
|
35
|
-
When I send the notification to "mobile_app_samsung_s25_fe"
|
|
36
|
-
Then the notification should be sent successfully
|
|
37
|
-
And the notification data should have priority "high"
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
Feature: Service Calls
|
|
2
|
-
As a Home Assistant user
|
|
3
|
-
I want to call Home Assistant services
|
|
4
|
-
So that I can control my devices
|
|
5
|
-
|
|
6
|
-
Scenario: Call service with domain and service name
|
|
7
|
-
Given a Home Assistant connection
|
|
8
|
-
When I call service "light.turn_on"
|
|
9
|
-
Then the service should be called successfully
|
|
10
|
-
And the request should go to "/services/light/turn_on"
|
|
11
|
-
|
|
12
|
-
Scenario: Call service with target entity
|
|
13
|
-
Given a Home Assistant connection
|
|
14
|
-
When I call service "light.turn_on" targeting "light.living_room"
|
|
15
|
-
Then the entity_id should be included in the request
|
|
16
|
-
|
|
17
|
-
Scenario: Call service with service data
|
|
18
|
-
Given a Home Assistant connection
|
|
19
|
-
When I call service "light.turn_on" with brightness 255
|
|
20
|
-
Then the brightness should be included in the request
|
|
21
|
-
|
|
22
|
-
Scenario: Call service targeting multiple entities
|
|
23
|
-
Given a Home Assistant connection
|
|
24
|
-
When I call service "light.turn_off" targeting multiple entities
|
|
25
|
-
Then all entity IDs should be included in the request
|
|
26
|
-
|
|
27
|
-
Scenario: Call climate service with temperature
|
|
28
|
-
Given a Home Assistant connection
|
|
29
|
-
When I call service "climate.set_temperature" with temperature 22
|
|
30
|
-
Then the temperature should be included in the request
|
|
31
|
-
|
|
32
|
-
Scenario: Restart Home Assistant server
|
|
33
|
-
Given a Home Assistant connection
|
|
34
|
-
When I call the restart server operation
|
|
35
|
-
Then the homeassistant.restart service should be called
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
Feature: State Retrieval
|
|
2
|
-
As a Home Assistant user
|
|
3
|
-
I want to retrieve entity states
|
|
4
|
-
So that I can monitor my smart home devices
|
|
5
|
-
|
|
6
|
-
Scenario: Get all entity states
|
|
7
|
-
Given a Home Assistant with multiple entities
|
|
8
|
-
When I get all states
|
|
9
|
-
Then I should receive all entity states
|
|
10
|
-
And the states API should be called
|
|
11
|
-
|
|
12
|
-
Scenario: Get state of specific entity
|
|
13
|
-
Given an entity "light.living_room" exists
|
|
14
|
-
When I get the state of "light.living_room"
|
|
15
|
-
Then I should receive the entity state
|
|
16
|
-
And the state should include entity_id, state, and attributes
|
|
17
|
-
|
|
18
|
-
Scenario: Get state of non-existent entity
|
|
19
|
-
Given an entity does not exist
|
|
20
|
-
When I get the state of "nonexistent.entity"
|
|
21
|
-
Then I should receive null
|
|
22
|
-
|
|
23
|
-
Scenario: Handle API error gracefully
|
|
24
|
-
Given the API returns a 500 error
|
|
25
|
-
When I get the state of "sensor.temperature"
|
|
26
|
-
Then it should throw an API error
|
|
27
|
-
|
|
28
|
-
Scenario: Get all sensors
|
|
29
|
-
Given a Home Assistant with sensors and other entities
|
|
30
|
-
When I get all sensors
|
|
31
|
-
Then I should only receive sensor and binary_sensor entities
|
|
32
|
-
And other entity types should be excluded
|
|
33
|
-
|
|
34
|
-
Scenario: Get sensors when none exist
|
|
35
|
-
Given a Home Assistant with no sensors
|
|
36
|
-
When I get all sensors
|
|
37
|
-
Then I should receive an empty array
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"openapi": "3.1.0",
|
|
3
|
-
"info": {
|
|
4
|
-
"title": "Home Assistant MCP Tools",
|
|
5
|
-
"description": "MCP server for Home Assistant - exposes entity states and service calls",
|
|
6
|
-
"version": "1.6.0"
|
|
7
|
-
},
|
|
8
|
-
"servers": [
|
|
9
|
-
{
|
|
10
|
-
"url": "http://__BASE_URL__"
|
|
11
|
-
}
|
|
12
|
-
],
|
|
13
|
-
"paths": {
|
|
14
|
-
"/api/states": {
|
|
15
|
-
"get": {
|
|
16
|
-
"operationId": "getStates",
|
|
17
|
-
"summary": "Get all entity states from Home Assistant",
|
|
18
|
-
"responses": {
|
|
19
|
-
"200": {
|
|
20
|
-
"description": "List of all entity states",
|
|
21
|
-
"content": {
|
|
22
|
-
"application/json": {
|
|
23
|
-
"schema": {
|
|
24
|
-
"type": "array",
|
|
25
|
-
"items": {
|
|
26
|
-
"$ref": "#/components/schemas/EntityState"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
"/api/states/{entity_id}": {
|
|
36
|
-
"get": {
|
|
37
|
-
"operationId": "getState",
|
|
38
|
-
"summary": "Get state of a specific entity",
|
|
39
|
-
"parameters": [
|
|
40
|
-
{
|
|
41
|
-
"name": "entity_id",
|
|
42
|
-
"in": "path",
|
|
43
|
-
"required": true,
|
|
44
|
-
"schema": {
|
|
45
|
-
"type": "string"
|
|
46
|
-
},
|
|
47
|
-
"description": "Entity ID (e.g., light.living_room)"
|
|
48
|
-
}
|
|
49
|
-
],
|
|
50
|
-
"responses": {
|
|
51
|
-
"200": {
|
|
52
|
-
"description": "Entity state",
|
|
53
|
-
"content": {
|
|
54
|
-
"application/json": {
|
|
55
|
-
"schema": {
|
|
56
|
-
"$ref": "#/components/schemas/EntityState"
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
"/api/services/{domain}/{service}": {
|
|
65
|
-
"post": {
|
|
66
|
-
"operationId": "callService",
|
|
67
|
-
"summary": "Call a Home Assistant service",
|
|
68
|
-
"parameters": [
|
|
69
|
-
{
|
|
70
|
-
"name": "domain",
|
|
71
|
-
"in": "path",
|
|
72
|
-
"required": true,
|
|
73
|
-
"schema": {
|
|
74
|
-
"type": "string"
|
|
75
|
-
},
|
|
76
|
-
"description": "Service domain (e.g., light, switch)"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"name": "service",
|
|
80
|
-
"in": "path",
|
|
81
|
-
"required": true,
|
|
82
|
-
"schema": {
|
|
83
|
-
"type": "string"
|
|
84
|
-
},
|
|
85
|
-
"description": "Service name (e.g., turn_on, turn_off)"
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
"requestBody": {
|
|
89
|
-
"content": {
|
|
90
|
-
"application/json": {
|
|
91
|
-
"schema": {
|
|
92
|
-
"type": "object",
|
|
93
|
-
"properties": {
|
|
94
|
-
"entity_id": {
|
|
95
|
-
"type": "string",
|
|
96
|
-
"description": "Target entity ID"
|
|
97
|
-
},
|
|
98
|
-
"data": {
|
|
99
|
-
"type": "object",
|
|
100
|
-
"description": "Service data"
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
"responses": {
|
|
108
|
-
"200": {
|
|
109
|
-
"description": "Service call result"
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
"/api/sensors": {
|
|
115
|
-
"get": {
|
|
116
|
-
"operationId": "getAllSensors",
|
|
117
|
-
"summary": "Get all sensor and binary_sensor states",
|
|
118
|
-
"responses": {
|
|
119
|
-
"200": {
|
|
120
|
-
"description": "List of sensor states",
|
|
121
|
-
"content": {
|
|
122
|
-
"application/json": {
|
|
123
|
-
"schema": {
|
|
124
|
-
"type": "array",
|
|
125
|
-
"items": {
|
|
126
|
-
"$ref": "#/components/schemas/EntityState"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
"/api/entities/{domain}": {
|
|
136
|
-
"get": {
|
|
137
|
-
"operationId": "getEntitiesByDomain",
|
|
138
|
-
"summary": "Get all entities for a specific domain",
|
|
139
|
-
"parameters": [
|
|
140
|
-
{
|
|
141
|
-
"name": "domain",
|
|
142
|
-
"in": "path",
|
|
143
|
-
"required": true,
|
|
144
|
-
"schema": {
|
|
145
|
-
"type": "string"
|
|
146
|
-
},
|
|
147
|
-
"description": "Domain name (e.g., light, sensor)"
|
|
148
|
-
}
|
|
149
|
-
],
|
|
150
|
-
"responses": {
|
|
151
|
-
"200": {
|
|
152
|
-
"description": "List of entities in domain",
|
|
153
|
-
"content": {
|
|
154
|
-
"application/json": {
|
|
155
|
-
"schema": {
|
|
156
|
-
"type": "array",
|
|
157
|
-
"items": {
|
|
158
|
-
"$ref": "#/components/schemas/EntityState"
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
"/api/search": {
|
|
168
|
-
"get": {
|
|
169
|
-
"operationId": "searchEntities",
|
|
170
|
-
"summary": "Search entities by name or ID",
|
|
171
|
-
"parameters": [
|
|
172
|
-
{
|
|
173
|
-
"name": "q",
|
|
174
|
-
"in": "query",
|
|
175
|
-
"required": true,
|
|
176
|
-
"schema": {
|
|
177
|
-
"type": "string"
|
|
178
|
-
},
|
|
179
|
-
"description": "Search query"
|
|
180
|
-
}
|
|
181
|
-
],
|
|
182
|
-
"responses": {
|
|
183
|
-
"200": {
|
|
184
|
-
"description": "Matching entities",
|
|
185
|
-
"content": {
|
|
186
|
-
"application/json": {
|
|
187
|
-
"schema": {
|
|
188
|
-
"type": "array",
|
|
189
|
-
"items": {
|
|
190
|
-
"$ref": "#/components/schemas/EntityState"
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
"/api/history/{entity_id}": {
|
|
200
|
-
"get": {
|
|
201
|
-
"operationId": "getHistory",
|
|
202
|
-
"summary": "Get historical data for an entity",
|
|
203
|
-
"parameters": [
|
|
204
|
-
{
|
|
205
|
-
"name": "entity_id",
|
|
206
|
-
"in": "path",
|
|
207
|
-
"required": true,
|
|
208
|
-
"schema": {
|
|
209
|
-
"type": "string"
|
|
210
|
-
},
|
|
211
|
-
"description": "Entity ID"
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
"name": "hours",
|
|
215
|
-
"in": "query",
|
|
216
|
-
"schema": {
|
|
217
|
-
"type": "number",
|
|
218
|
-
"default": 24
|
|
219
|
-
},
|
|
220
|
-
"description": "Hours of history"
|
|
221
|
-
}
|
|
222
|
-
],
|
|
223
|
-
"responses": {
|
|
224
|
-
"200": {
|
|
225
|
-
"description": "Historical data",
|
|
226
|
-
"content": {
|
|
227
|
-
"application/json": {
|
|
228
|
-
"schema": {
|
|
229
|
-
"type": "array"
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
"/api/version": {
|
|
238
|
-
"get": {
|
|
239
|
-
"operationId": "getVersion",
|
|
240
|
-
"summary": "Get Home Assistant version information",
|
|
241
|
-
"responses": {
|
|
242
|
-
"200": {
|
|
243
|
-
"description": "Version information",
|
|
244
|
-
"content": {
|
|
245
|
-
"application/json": {
|
|
246
|
-
"schema": {
|
|
247
|
-
"type": "object",
|
|
248
|
-
"properties": {
|
|
249
|
-
"ha_version": {
|
|
250
|
-
"type": "string",
|
|
251
|
-
"description": "Home Assistant version"
|
|
252
|
-
},
|
|
253
|
-
"mcp_version": {
|
|
254
|
-
"type": "string",
|
|
255
|
-
"description": "MCP server version"
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
"components": {
|
|
267
|
-
"schemas": {
|
|
268
|
-
"EntityState": {
|
|
269
|
-
"type": "object",
|
|
270
|
-
"properties": {
|
|
271
|
-
"entity_id": {
|
|
272
|
-
"type": "string"
|
|
273
|
-
},
|
|
274
|
-
"state": {
|
|
275
|
-
"type": "string"
|
|
276
|
-
},
|
|
277
|
-
"attributes": {
|
|
278
|
-
"type": "object"
|
|
279
|
-
},
|
|
280
|
-
"last_changed": {
|
|
281
|
-
"type": "string"
|
|
282
|
-
},
|
|
283
|
-
"last_updated": {
|
|
284
|
-
"type": "string"
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getAutomationTrace goes over the WebSocket (`trace/list`), keyed by the
|
|
3
|
-
* automation's config id — there is no REST trace endpoint in Home Assistant.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
7
|
-
|
|
8
|
-
import { AutomationOperations } from '../../src/haClient/automations.js';
|
|
9
|
-
import type { StateOperations } from '../../src/haClient/states.js';
|
|
10
|
-
|
|
11
|
-
function setup(state: unknown, traces: unknown = []) {
|
|
12
|
-
const stateOps = { getState: vi.fn().mockResolvedValue(state) } as unknown as StateOperations;
|
|
13
|
-
const wsCommand = vi.fn().mockResolvedValue(traces);
|
|
14
|
-
const request = { get: vi.fn() };
|
|
15
|
-
const ops = new AutomationOperations(stateOps, undefined, request as never, wsCommand as never);
|
|
16
|
-
return { ops, wsCommand, request };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const automation = (attributes: Record<string, unknown>) => ({ entity_id: 'automation.relay', state: 'on', attributes });
|
|
20
|
-
|
|
21
|
-
const run = (id: string, start: string) => ({ run_id: id, timestamp: { start, finish: start }, trigger: 'state of sensor.x' });
|
|
22
|
-
|
|
23
|
-
describe('AutomationOperations.getAutomationTrace', () => {
|
|
24
|
-
it('lists traces by the automation id attribute, newest first, over the WebSocket only', async () => {
|
|
25
|
-
const { ops, wsCommand, request } = setup(automation({ id: '1700000000000' }), [
|
|
26
|
-
run('a', '2026-10-07T08:00:00Z'),
|
|
27
|
-
run('c', '2026-10-07T10:00:00Z'),
|
|
28
|
-
run('b', '2026-10-07T09:00:00Z'),
|
|
29
|
-
]);
|
|
30
|
-
|
|
31
|
-
const traces = await ops.getAutomationTrace('automation.relay');
|
|
32
|
-
|
|
33
|
-
expect(wsCommand).toHaveBeenCalledWith({ type: 'trace/list', domain: 'automation', item_id: '1700000000000' });
|
|
34
|
-
expect(traces.map((t) => t.run_id)).toEqual(['c', 'b', 'a']);
|
|
35
|
-
expect(request.get).not.toHaveBeenCalled();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('returns at most `limit` runs (default 5)', async () => {
|
|
39
|
-
const many = Array.from({ length: 8 }, (_, i) => run(String(i), `2026-10-07T0${i}:00:00Z`));
|
|
40
|
-
const { ops } = setup(automation({ id: 7 }), many);
|
|
41
|
-
|
|
42
|
-
expect(await ops.getAutomationTrace('automation.relay')).toHaveLength(5);
|
|
43
|
-
expect((await ops.getAutomationTrace('automation.relay', 2)).map((t) => t.run_id)).toEqual(['7', '6']);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('explains that a YAML automation without an id has no traces', async () => {
|
|
47
|
-
const { ops, wsCommand } = setup(automation({ friendly_name: 'Relay' }));
|
|
48
|
-
|
|
49
|
-
await expect(ops.getAutomationTrace('automation.relay')).rejects.toThrow(/has no 'id'.*no traces/);
|
|
50
|
-
expect(wsCommand).not.toHaveBeenCalled();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('reports an unknown automation', async () => {
|
|
54
|
-
const { ops, wsCommand } = setup(null);
|
|
55
|
-
|
|
56
|
-
await expect(ops.getAutomationTrace('automation.nope')).rejects.toThrow('Automation automation.nope not found');
|
|
57
|
-
expect(wsCommand).not.toHaveBeenCalled();
|
|
58
|
-
});
|
|
59
|
-
});
|