[Feature]: Bind Home Assistant sensors to storage locations (dryboxes/bins) (#2827)

This commit is contained in:
MagicMelody84
2026-08-25 12:17:23 +02:00
committed by GitHub
parent 5dd7bd213f
commit 54af3146a3
75 changed files with 8146 additions and 342 deletions
+82
View File
@@ -1438,6 +1438,12 @@ export interface AppSettings {
obico_enabled_printers: string;
// Inventory forecasting global lead time
forecast_global_lead_time_days: number;
location_sensor_poll_interval: number;
// JSON map of sensor category → {alertAbove, alertBelow, notifyOnAlert},
// seeding new storage-location sensor bindings. Empty = built-in defaults.
// Server-backed so two admins seed the same alert rules and a restore
// brings them back; see utils/locationSensorDefaults.ts.
location_sensor_alert_defaults: string;
}
export type AppSettingsUpdate = Partial<AppSettings>;
@@ -2350,6 +2356,62 @@ export interface PrinterHASensorCreate {
export type PrinterHASensorUpdate = Partial<Omit<PrinterHASensorCreate, 'printer_id'>>;
export interface LocationHASensor {
id: number;
location_id: number;
name: string;
entity_id: string;
kind: 'binary' | 'numeric';
device_class: string | null;
unit: string | null;
alert_state: 'on' | 'off' | null;
alert_above: number | null;
alert_below: number | null;
notify_on_alert: boolean;
show_on_card: boolean;
sort_order: number;
last_state: string | null;
last_changed: string | null;
last_checked: string | null;
created_at: string;
updated_at: string;
}
export interface LocationHASensorReading {
id: number;
name: string;
entity_id: string;
kind: 'binary' | 'numeric';
device_class: string | null;
unit: string | null;
state: string | null;
value: number | null;
alerting: boolean;
reachable: boolean;
alert_state: string | null;
alert_above: number | null;
alert_below: number | null;
last_changed: string | null;
show_on_card: boolean;
}
export interface LocationHASensorCreate {
location_id: number;
name: string;
entity_id: string;
kind: 'binary' | 'numeric';
device_class?: string | null;
unit?: string | null;
alert_state?: 'on' | 'off' | null;
alert_above?: number | null;
alert_below?: number | null;
notify_on_alert?: boolean;
show_on_card?: boolean;
sort_order?: number;
}
export type LocationHASensorUpdate = Partial<Omit<LocationHASensorCreate, 'location_id'>>;
// An entity offered by the binding picker.
export interface HADisplayEntity {
entity_id: string;
@@ -2831,6 +2893,7 @@ export interface NotificationProvider {
// Bed cooled
on_bed_cooled: boolean;
on_ha_sensor_alert: boolean;
on_location_ha_sensor_alert: boolean;
// First layer complete
on_first_layer_complete: boolean;
// Inventory stock alerts
@@ -2894,6 +2957,7 @@ export interface NotificationProviderCreate {
// Bed cooled
on_bed_cooled?: boolean;
on_ha_sensor_alert?: boolean;
on_location_ha_sensor_alert?: boolean;
// First layer complete
on_first_layer_complete?: boolean;
// Inventory stock alerts
@@ -2950,6 +3014,7 @@ export interface NotificationProviderUpdate {
// Bed cooled
on_bed_cooled?: boolean;
on_ha_sensor_alert?: boolean;
on_location_ha_sensor_alert?: boolean;
// First layer complete
on_first_layer_complete?: boolean;
// Inventory stock alerts
@@ -5737,6 +5802,23 @@ export const api = {
deleteHASensor: (id: number) =>
request<{ message: string }>(`/ha-sensors/${id}`, { method: 'DELETE' }),
getLocationHASensors: (locationId?: number) =>
request<LocationHASensor[]>(`/location-ha-sensors/${locationId ? `?location_id=${locationId}` : ''}`),
getLocationHASensorReadings: (locationId: number, showOnCard = true) =>
request<LocationHASensorReading[]>(
`/location-ha-sensors/by-location/${locationId}/readings?show_on_card=${showOnCard}`
),
getBindableLocationHAEntities: (search?: string) => {
const params = search ? `?search=${encodeURIComponent(search)}` : '';
return request<HADisplayEntity[]>(`/location-ha-sensors/entities${params}`);
},
createLocationHASensor: (data: LocationHASensorCreate) =>
request<LocationHASensor>('/location-ha-sensors/', { method: 'POST', body: JSON.stringify(data) }),
updateLocationHASensor: (id: number, data: LocationHASensorUpdate) =>
request<LocationHASensor>(`/location-ha-sensors/${id}`, { method: 'PATCH', body: JSON.stringify(data) }),
deleteLocationHASensor: (id: number) =>
request<{ message: string }>(`/location-ha-sensors/${id}`, { method: 'DELETE' }),
// REST smart plug
testRESTConnection: (url: string, method: string = 'GET', headers?: string | null) =>
request<{ success: boolean; error: string | null }>('/smart-plugs/rest/test-connection', {