@camstack/addon-provider-bosch 0.1.17 → 0.1.19
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/dist/{account-integration-offline-W-dxoTT1.mjs → account-integration-offline-B9spxppg.mjs} +1 -1
- package/dist/{account-integration-offline-pY2Ojv8k.js → account-integration-offline-D5EEH5Xn.js} +1 -1
- package/dist/{dist-D6D2JO8x.js → dist-C5fLGNXK.js} +261 -120
- package/dist/{dist-C8QaBSuL.mjs → dist-LGjOHvFG.mjs} +256 -121
- package/dist/home-connect/addon.js +79 -7
- package/dist/home-connect/addon.mjs +79 -7
- package/dist/homecom/addon.js +2 -2
- package/dist/homecom/addon.mjs +2 -2
- package/dist/shc/addon.js +1 -1
- package/dist/shc/addon.mjs +1 -1
- package/package.json +4 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("../dist-
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_dist = require("../dist-C5fLGNXK.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-D5EEH5Xn.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_tls = require("node:tls");
|
|
6
6
|
let node_zlib = require("node:zlib");
|
|
@@ -3826,8 +3826,6 @@ var COLD_DISHWASHER_STATUS = {
|
|
|
3826
3826
|
localControlActive: null,
|
|
3827
3827
|
powerOn: null,
|
|
3828
3828
|
powerState: null,
|
|
3829
|
-
saltLevel: null,
|
|
3830
|
-
rinseAidLevel: null,
|
|
3831
3829
|
filterCleaningDue: null,
|
|
3832
3830
|
machineCareDue: null,
|
|
3833
3831
|
machineCareRemainingRuns: null,
|
|
@@ -3885,8 +3883,6 @@ function dishwasherStatusFromFeatures(input) {
|
|
|
3885
3883
|
localControlActive: boolOf(valueOf(input, findEntity(description, ["status"], ["LocalControlActive"]))),
|
|
3886
3884
|
powerOn: powerRaw === null ? null : powerRaw === "On",
|
|
3887
3885
|
powerState: powerRaw,
|
|
3888
|
-
saltLevel: consumableFromEvents(input, ["SaltNearlyEmpty"], ["SaltEmpty", "SaltLack"]),
|
|
3889
|
-
rinseAidLevel: consumableFromEvents(input, ["RinseAidNearlyEmpty"], ["RinseAidEmpty", "RinseAidLack"]),
|
|
3890
3886
|
filterCleaningDue: reminderDue(input, [
|
|
3891
3887
|
"SmartFilterCleaningReminder",
|
|
3892
3888
|
"CheckFilterSystem",
|
|
@@ -3987,6 +3983,44 @@ function dishwasherOptionsFromDescription(input) {
|
|
|
3987
3983
|
var HC_COMMAND_PAUSE = "PauseProgram";
|
|
3988
3984
|
var HC_COMMAND_RESUME = "ResumeProgram";
|
|
3989
3985
|
var HC_COMMAND_STOP = "AbortProgram";
|
|
3986
|
+
/** The dishwasher supplies, by the events that report them. */
|
|
3987
|
+
var DISHWASHER_SUPPLIES = [{
|
|
3988
|
+
key: "salt",
|
|
3989
|
+
label: "Salt",
|
|
3990
|
+
nearlyEmpty: ["SaltNearlyEmpty"],
|
|
3991
|
+
empty: ["SaltEmpty", "SaltLack"]
|
|
3992
|
+
}, {
|
|
3993
|
+
key: "rinseAid",
|
|
3994
|
+
label: "Rinse aid",
|
|
3995
|
+
nearlyEmpty: ["RinseAidNearlyEmpty"],
|
|
3996
|
+
empty: ["RinseAidEmpty", "RinseAidLack"]
|
|
3997
|
+
}];
|
|
3998
|
+
/**
|
|
3999
|
+
* The dishwasher's `consumables` items (D915): salt and rinse aid as `supply`
|
|
4000
|
+
* items, for each the appliance's description lists an event for. Their
|
|
4001
|
+
* status comes from those events (`consumableFromEvents`); none reported is
|
|
4002
|
+
* `null` (unknown), never `ok`. Neither is resettable — refilling is the reset.
|
|
4003
|
+
*
|
|
4004
|
+
* `null` while the appliance is offline or undescribed: nothing is known NOW,
|
|
4005
|
+
* and the `consumables` slice is restored — the last observation stays rather
|
|
4006
|
+
* than being overwritten with unknowns. Pure.
|
|
4007
|
+
*/
|
|
4008
|
+
function dishwasherConsumablesFromFeatures(view) {
|
|
4009
|
+
if (availabilityOf(view) !== "available") return null;
|
|
4010
|
+
return DISHWASHER_SUPPLIES.flatMap(({ key, label, nearlyEmpty, empty }) => {
|
|
4011
|
+
if (eventStates(view, [...nearlyEmpty, ...empty]).length === 0) return [];
|
|
4012
|
+
return [{
|
|
4013
|
+
key,
|
|
4014
|
+
label,
|
|
4015
|
+
level: null,
|
|
4016
|
+
status: consumableFromEvents(view, nearlyEmpty, empty),
|
|
4017
|
+
kind: "supply",
|
|
4018
|
+
form: "product",
|
|
4019
|
+
lastResetAt: null,
|
|
4020
|
+
resettable: false
|
|
4021
|
+
}];
|
|
4022
|
+
});
|
|
4023
|
+
}
|
|
3990
4024
|
//#endregion
|
|
3991
4025
|
//#region src/home-connect/home-connect-child-bindings.ts
|
|
3992
4026
|
/** The capability a bound child registers. */
|
|
@@ -4577,6 +4611,15 @@ var homeConnectDishwasherSchema = require_dist.object({
|
|
|
4577
4611
|
integrationId: require_dist.string().optional()
|
|
4578
4612
|
});
|
|
4579
4613
|
var DISH_CAP = "dishwasher";
|
|
4614
|
+
var CONSUMABLES_CAP = "consumables";
|
|
4615
|
+
var CONSUMABLES_EMPTY = {
|
|
4616
|
+
items: [],
|
|
4617
|
+
lastChangedAt: 0,
|
|
4618
|
+
lastFetchedAt: 0
|
|
4619
|
+
};
|
|
4620
|
+
function sameItems(a, b) {
|
|
4621
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
4622
|
+
}
|
|
4580
4623
|
/** The option short names of the boolean setters, in the spellings an appliance uses. */
|
|
4581
4624
|
var OPTION_NAMES = {
|
|
4582
4625
|
halfLoad: ["HalfLoad"],
|
|
@@ -4603,6 +4646,7 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
|
|
|
4603
4646
|
async onActivate() {
|
|
4604
4647
|
await super.onActivate();
|
|
4605
4648
|
this.registerDishwasherCap();
|
|
4649
|
+
this.registerConsumablesCap();
|
|
4606
4650
|
this.runtimeState.setCapState(DISH_CAP, COLD_DISHWASHER_STATUS);
|
|
4607
4651
|
this.markOnline(false);
|
|
4608
4652
|
this.#unwatch = homeConnectConnections.watch(this.#brokerId, this.#haId, (event) => this.recomputeSlice(event));
|
|
@@ -4627,13 +4671,41 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
|
|
|
4627
4671
|
recomputeSlice(event) {
|
|
4628
4672
|
const previous = this.runtimeState.getCapState(DISH_CAP);
|
|
4629
4673
|
const lastValueAt = event.kind === "feature" && !event.key.startsWith("HomeConnect.Info.") && !event.key.startsWith("HomeConnect.Network.") ? Date.now() : previous?.lastFetchedAt ?? 0;
|
|
4674
|
+
const view = this.view();
|
|
4630
4675
|
const slice = dishwasherStatusFromFeatures({
|
|
4631
|
-
...
|
|
4676
|
+
...view,
|
|
4632
4677
|
lastValueAt
|
|
4633
4678
|
});
|
|
4634
4679
|
this.runtimeState.setCapState(DISH_CAP, slice);
|
|
4680
|
+
this.writeConsumables(dishwasherConsumablesFromFeatures(view));
|
|
4635
4681
|
this.markOnline(slice.availability !== "offline");
|
|
4636
4682
|
}
|
|
4683
|
+
/**
|
|
4684
|
+
* Salt and rinse aid, as `consumables` items (D915). Written only when they
|
|
4685
|
+
* changed; `null` (offline / undescribed) and an empty list write nothing —
|
|
4686
|
+
* the slice is restored, and "nothing known now" must not erase the last
|
|
4687
|
+
* observation.
|
|
4688
|
+
*/
|
|
4689
|
+
writeConsumables(items) {
|
|
4690
|
+
if (items === null || items.length === 0) return;
|
|
4691
|
+
const previous = this.runtimeState.getCapState(CONSUMABLES_CAP);
|
|
4692
|
+
if (previous !== void 0 && sameItems(previous.items, items)) return;
|
|
4693
|
+
const now = Date.now();
|
|
4694
|
+
const next = {
|
|
4695
|
+
items,
|
|
4696
|
+
lastChangedAt: now,
|
|
4697
|
+
lastFetchedAt: now
|
|
4698
|
+
};
|
|
4699
|
+
this.runtimeState.setCapState(CONSUMABLES_CAP, next);
|
|
4700
|
+
}
|
|
4701
|
+
registerConsumablesCap() {
|
|
4702
|
+
this.ctx.registerNativeCap(require_dist.consumablesCapability, {
|
|
4703
|
+
getStatus: async () => this.runtimeState.getCapState(CONSUMABLES_CAP) ?? CONSUMABLES_EMPTY,
|
|
4704
|
+
reset: async ({ key }) => {
|
|
4705
|
+
throw new Error(`"${key}" has no reset on a dishwasher — refilling it is the reset`);
|
|
4706
|
+
}
|
|
4707
|
+
});
|
|
4708
|
+
}
|
|
4637
4709
|
requireClient() {
|
|
4638
4710
|
const client = this.client();
|
|
4639
4711
|
if (!client) throw new Error("Home Connect client unavailable — the integration is not connected");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-
|
|
1
|
+
import { C as customAction, D as _enum, E as isSecretMarkerLike, F as unknown, I as EventCategory, M as record, N as string, O as array, P as union, S as createEvent, T as isSecretMarker, a as binaryCapability, b as DeviceType, c as consumablesCapability, d as enumSensorCapability, f as eventEmitterCapability, h as powerMeterCapability, j as object, k as literal, l as deviceAdoptionCapability, m as numericSensorCapability, n as BaseDeviceProvider, r as DishwasherOperationStateSchema, s as connectionTestCapability, t as BaseDevice, u as dishwasherCapability, w as defineCustomActions, x as errMsg, y as DeviceRole } from "../dist-LGjOHvFG.mjs";
|
|
2
|
+
import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-B9spxppg.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { connect } from "node:tls";
|
|
5
5
|
import { inflateRawSync } from "node:zlib";
|
|
@@ -3825,8 +3825,6 @@ var COLD_DISHWASHER_STATUS = {
|
|
|
3825
3825
|
localControlActive: null,
|
|
3826
3826
|
powerOn: null,
|
|
3827
3827
|
powerState: null,
|
|
3828
|
-
saltLevel: null,
|
|
3829
|
-
rinseAidLevel: null,
|
|
3830
3828
|
filterCleaningDue: null,
|
|
3831
3829
|
machineCareDue: null,
|
|
3832
3830
|
machineCareRemainingRuns: null,
|
|
@@ -3884,8 +3882,6 @@ function dishwasherStatusFromFeatures(input) {
|
|
|
3884
3882
|
localControlActive: boolOf(valueOf(input, findEntity(description, ["status"], ["LocalControlActive"]))),
|
|
3885
3883
|
powerOn: powerRaw === null ? null : powerRaw === "On",
|
|
3886
3884
|
powerState: powerRaw,
|
|
3887
|
-
saltLevel: consumableFromEvents(input, ["SaltNearlyEmpty"], ["SaltEmpty", "SaltLack"]),
|
|
3888
|
-
rinseAidLevel: consumableFromEvents(input, ["RinseAidNearlyEmpty"], ["RinseAidEmpty", "RinseAidLack"]),
|
|
3889
3885
|
filterCleaningDue: reminderDue(input, [
|
|
3890
3886
|
"SmartFilterCleaningReminder",
|
|
3891
3887
|
"CheckFilterSystem",
|
|
@@ -3986,6 +3982,44 @@ function dishwasherOptionsFromDescription(input) {
|
|
|
3986
3982
|
var HC_COMMAND_PAUSE = "PauseProgram";
|
|
3987
3983
|
var HC_COMMAND_RESUME = "ResumeProgram";
|
|
3988
3984
|
var HC_COMMAND_STOP = "AbortProgram";
|
|
3985
|
+
/** The dishwasher supplies, by the events that report them. */
|
|
3986
|
+
var DISHWASHER_SUPPLIES = [{
|
|
3987
|
+
key: "salt",
|
|
3988
|
+
label: "Salt",
|
|
3989
|
+
nearlyEmpty: ["SaltNearlyEmpty"],
|
|
3990
|
+
empty: ["SaltEmpty", "SaltLack"]
|
|
3991
|
+
}, {
|
|
3992
|
+
key: "rinseAid",
|
|
3993
|
+
label: "Rinse aid",
|
|
3994
|
+
nearlyEmpty: ["RinseAidNearlyEmpty"],
|
|
3995
|
+
empty: ["RinseAidEmpty", "RinseAidLack"]
|
|
3996
|
+
}];
|
|
3997
|
+
/**
|
|
3998
|
+
* The dishwasher's `consumables` items (D915): salt and rinse aid as `supply`
|
|
3999
|
+
* items, for each the appliance's description lists an event for. Their
|
|
4000
|
+
* status comes from those events (`consumableFromEvents`); none reported is
|
|
4001
|
+
* `null` (unknown), never `ok`. Neither is resettable — refilling is the reset.
|
|
4002
|
+
*
|
|
4003
|
+
* `null` while the appliance is offline or undescribed: nothing is known NOW,
|
|
4004
|
+
* and the `consumables` slice is restored — the last observation stays rather
|
|
4005
|
+
* than being overwritten with unknowns. Pure.
|
|
4006
|
+
*/
|
|
4007
|
+
function dishwasherConsumablesFromFeatures(view) {
|
|
4008
|
+
if (availabilityOf(view) !== "available") return null;
|
|
4009
|
+
return DISHWASHER_SUPPLIES.flatMap(({ key, label, nearlyEmpty, empty }) => {
|
|
4010
|
+
if (eventStates(view, [...nearlyEmpty, ...empty]).length === 0) return [];
|
|
4011
|
+
return [{
|
|
4012
|
+
key,
|
|
4013
|
+
label,
|
|
4014
|
+
level: null,
|
|
4015
|
+
status: consumableFromEvents(view, nearlyEmpty, empty),
|
|
4016
|
+
kind: "supply",
|
|
4017
|
+
form: "product",
|
|
4018
|
+
lastResetAt: null,
|
|
4019
|
+
resettable: false
|
|
4020
|
+
}];
|
|
4021
|
+
});
|
|
4022
|
+
}
|
|
3989
4023
|
//#endregion
|
|
3990
4024
|
//#region src/home-connect/home-connect-child-bindings.ts
|
|
3991
4025
|
/** The capability a bound child registers. */
|
|
@@ -4576,6 +4610,15 @@ var homeConnectDishwasherSchema = object({
|
|
|
4576
4610
|
integrationId: string().optional()
|
|
4577
4611
|
});
|
|
4578
4612
|
var DISH_CAP = "dishwasher";
|
|
4613
|
+
var CONSUMABLES_CAP = "consumables";
|
|
4614
|
+
var CONSUMABLES_EMPTY = {
|
|
4615
|
+
items: [],
|
|
4616
|
+
lastChangedAt: 0,
|
|
4617
|
+
lastFetchedAt: 0
|
|
4618
|
+
};
|
|
4619
|
+
function sameItems(a, b) {
|
|
4620
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
4621
|
+
}
|
|
4579
4622
|
/** The option short names of the boolean setters, in the spellings an appliance uses. */
|
|
4580
4623
|
var OPTION_NAMES = {
|
|
4581
4624
|
halfLoad: ["HalfLoad"],
|
|
@@ -4602,6 +4645,7 @@ var HomeConnectDishwasherDevice = class extends BaseDevice {
|
|
|
4602
4645
|
async onActivate() {
|
|
4603
4646
|
await super.onActivate();
|
|
4604
4647
|
this.registerDishwasherCap();
|
|
4648
|
+
this.registerConsumablesCap();
|
|
4605
4649
|
this.runtimeState.setCapState(DISH_CAP, COLD_DISHWASHER_STATUS);
|
|
4606
4650
|
this.markOnline(false);
|
|
4607
4651
|
this.#unwatch = homeConnectConnections.watch(this.#brokerId, this.#haId, (event) => this.recomputeSlice(event));
|
|
@@ -4626,13 +4670,41 @@ var HomeConnectDishwasherDevice = class extends BaseDevice {
|
|
|
4626
4670
|
recomputeSlice(event) {
|
|
4627
4671
|
const previous = this.runtimeState.getCapState(DISH_CAP);
|
|
4628
4672
|
const lastValueAt = event.kind === "feature" && !event.key.startsWith("HomeConnect.Info.") && !event.key.startsWith("HomeConnect.Network.") ? Date.now() : previous?.lastFetchedAt ?? 0;
|
|
4673
|
+
const view = this.view();
|
|
4629
4674
|
const slice = dishwasherStatusFromFeatures({
|
|
4630
|
-
...
|
|
4675
|
+
...view,
|
|
4631
4676
|
lastValueAt
|
|
4632
4677
|
});
|
|
4633
4678
|
this.runtimeState.setCapState(DISH_CAP, slice);
|
|
4679
|
+
this.writeConsumables(dishwasherConsumablesFromFeatures(view));
|
|
4634
4680
|
this.markOnline(slice.availability !== "offline");
|
|
4635
4681
|
}
|
|
4682
|
+
/**
|
|
4683
|
+
* Salt and rinse aid, as `consumables` items (D915). Written only when they
|
|
4684
|
+
* changed; `null` (offline / undescribed) and an empty list write nothing —
|
|
4685
|
+
* the slice is restored, and "nothing known now" must not erase the last
|
|
4686
|
+
* observation.
|
|
4687
|
+
*/
|
|
4688
|
+
writeConsumables(items) {
|
|
4689
|
+
if (items === null || items.length === 0) return;
|
|
4690
|
+
const previous = this.runtimeState.getCapState(CONSUMABLES_CAP);
|
|
4691
|
+
if (previous !== void 0 && sameItems(previous.items, items)) return;
|
|
4692
|
+
const now = Date.now();
|
|
4693
|
+
const next = {
|
|
4694
|
+
items,
|
|
4695
|
+
lastChangedAt: now,
|
|
4696
|
+
lastFetchedAt: now
|
|
4697
|
+
};
|
|
4698
|
+
this.runtimeState.setCapState(CONSUMABLES_CAP, next);
|
|
4699
|
+
}
|
|
4700
|
+
registerConsumablesCap() {
|
|
4701
|
+
this.ctx.registerNativeCap(consumablesCapability, {
|
|
4702
|
+
getStatus: async () => this.runtimeState.getCapState(CONSUMABLES_CAP) ?? CONSUMABLES_EMPTY,
|
|
4703
|
+
reset: async ({ key }) => {
|
|
4704
|
+
throw new Error(`"${key}" has no reset on a dishwasher — refilling it is the reset`);
|
|
4705
|
+
}
|
|
4706
|
+
});
|
|
4707
|
+
}
|
|
4636
4708
|
requireClient() {
|
|
4637
4709
|
const client = this.client();
|
|
4638
4710
|
if (!client) throw new Error("Home Connect client unavailable — the integration is not connected");
|
package/dist/homecom/addon.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("../dist-
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_dist = require("../dist-C5fLGNXK.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-D5EEH5Xn.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
//#region src/homecom/custom-actions.ts
|
|
6
6
|
var homeComActions = require_dist.defineCustomActions({
|
package/dist/homecom/addon.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-
|
|
1
|
+
import { C as customAction, D as _enum, E as isSecretMarkerLike, I as EventCategory, N as string, T as isSecretMarker, b as DeviceType, j as object, k as literal, l as deviceAdoptionCapability, n as BaseDeviceProvider, o as climateControlCapability, s as connectionTestCapability, t as BaseDevice, v as waterHeaterCapability, w as defineCustomActions, x as errMsg } from "../dist-LGjOHvFG.mjs";
|
|
2
|
+
import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-B9spxppg.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
//#region src/homecom/custom-actions.ts
|
|
5
5
|
var homeComActions = defineCustomActions({
|
package/dist/shc/addon.js
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
3
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
4
|
//#endregion
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-C5fLGNXK.js");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_https = require("node:https");
|
|
8
8
|
let node_child_process = require("node:child_process");
|
package/dist/shc/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as number, C as customAction, D as _enum, I as EventCategory, N as string, O as array, _ as temperatureSensorCapability, b as DeviceType, g as switchCapability, i as batteryCapability, j as object, k as literal, l as deviceAdoptionCapability, n as BaseDeviceProvider, o as climateControlCapability, p as heatingValveCapability, s as connectionTestCapability, t as BaseDevice, w as defineCustomActions, x as errMsg } from "../dist-LGjOHvFG.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { request } from "node:https";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-bosch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Bosch smart-home device-provider addons for CamStack — SHC, Home Connect, and HomeCom cloud integrations (scaffold)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -81,6 +81,9 @@
|
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"name": "dishwasher"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "consumables"
|
|
84
87
|
}
|
|
85
88
|
]
|
|
86
89
|
},
|