ember-mug 0.1.3 → 0.1.5

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.
Files changed (41) hide show
  1. package/README.md +22 -15
  2. package/dist/cli.js +37 -7
  3. package/dist/components/App.d.ts +1 -1
  4. package/dist/components/App.js +65 -54
  5. package/dist/components/BatteryDisplay.d.ts +9 -3
  6. package/dist/components/BatteryDisplay.js +8 -19
  7. package/dist/components/ConnectionStatus.d.ts +7 -2
  8. package/dist/components/ConnectionStatus.js +5 -4
  9. package/dist/components/Header.d.ts +7 -2
  10. package/dist/components/Header.js +11 -3
  11. package/dist/components/HelpDisplay.d.ts +5 -2
  12. package/dist/components/HelpDisplay.js +8 -3
  13. package/dist/components/HorizontalRule.d.ts +2 -0
  14. package/dist/components/HorizontalRule.js +7 -0
  15. package/dist/components/Panel.d.ts +18 -0
  16. package/dist/components/Panel.js +57 -0
  17. package/dist/components/Presets.d.ts +8 -3
  18. package/dist/components/Presets.js +13 -8
  19. package/dist/components/SettingsView.d.ts +9 -3
  20. package/dist/components/SettingsView.js +90 -16
  21. package/dist/components/TemperatureControl.d.ts +8 -3
  22. package/dist/components/TemperatureControl.js +13 -18
  23. package/dist/components/TemperatureDisplay.d.ts +9 -3
  24. package/dist/components/TemperatureDisplay.js +9 -36
  25. package/dist/hooks/useMug.d.ts +3 -1
  26. package/dist/hooks/useMug.js +69 -22
  27. package/dist/lib/bluetooth.d.ts +2 -0
  28. package/dist/lib/bluetooth.js +8 -0
  29. package/dist/lib/mock-bluetooth.d.ts +65 -0
  30. package/dist/lib/mock-bluetooth.js +214 -0
  31. package/dist/lib/settings.d.ts +1 -1
  32. package/dist/lib/settings.js +20 -20
  33. package/dist/lib/theme.d.ts +135 -0
  34. package/dist/lib/theme.js +112 -0
  35. package/dist/lib/types.d.ts +0 -1
  36. package/dist/lib/types.js +12 -12
  37. package/dist/lib/utils.d.ts +7 -4
  38. package/dist/lib/utils.js +63 -40
  39. package/package.json +3 -1
  40. package/dist/components/ColorControl.d.ts +0 -9
  41. package/dist/components/ColorControl.js +0 -71
@@ -0,0 +1,214 @@
1
+ import { EventEmitter } from 'events';
2
+ import { LiquidState, TemperatureUnit, MIN_TEMP_CELSIUS, MAX_TEMP_CELSIUS, BATTERY_DRAIN_RATE_HEATING, BATTERY_DRAIN_RATE_MAINTAINING, BATTERY_CHARGE_RATE, } from './types.js';
3
+ const DEFAULT_CONFIG = {
4
+ initialBattery: 75,
5
+ initialCurrentTemp: 45,
6
+ initialTargetTemp: 55,
7
+ initialLiquidState: LiquidState.Cooling,
8
+ initiallyCharging: false,
9
+ mugName: 'Mock Ember Mug',
10
+ scanDelay: 1500,
11
+ connectionDelay: 800,
12
+ tempChangeRate: 0.5, // degrees per second
13
+ updateInterval: 1000,
14
+ };
15
+ export class MockBluetoothManager extends EventEmitter {
16
+ config;
17
+ isConnected = false;
18
+ simulationInterval = null;
19
+ lastUpdateTime = Date.now();
20
+ state;
21
+ constructor(config = {}) {
22
+ super();
23
+ this.config = { ...DEFAULT_CONFIG, ...config };
24
+ this.state = {
25
+ connected: false,
26
+ batteryLevel: this.config.initialBattery,
27
+ isCharging: this.config.initiallyCharging,
28
+ currentTemp: this.config.initialCurrentTemp,
29
+ targetTemp: this.config.initialTargetTemp,
30
+ liquidState: this.config.initialLiquidState,
31
+ temperatureUnit: TemperatureUnit.Celsius,
32
+ color: { r: 255, g: 147, b: 41, a: 255 }, // Default ember orange
33
+ mugName: '',
34
+ };
35
+ }
36
+ async startScanning() {
37
+ this.emit('scanning', true);
38
+ // Simulate finding a mug after a delay
39
+ setTimeout(() => {
40
+ this.emit('mugFound', this.config.mugName);
41
+ this.emit('scanning', false);
42
+ // Auto-connect after finding
43
+ setTimeout(() => {
44
+ this.connect();
45
+ }, this.config.connectionDelay);
46
+ }, this.config.scanDelay);
47
+ }
48
+ async stopScanning() {
49
+ this.emit('scanning', false);
50
+ }
51
+ async connect() {
52
+ this.isConnected = true;
53
+ this.state.connected = true;
54
+ this.state.mugName = this.config.mugName;
55
+ this.startSimulation();
56
+ this.emit('connected');
57
+ this.emitState();
58
+ }
59
+ startSimulation() {
60
+ this.lastUpdateTime = Date.now();
61
+ this.simulationInterval = setInterval(() => {
62
+ if (!this.isConnected)
63
+ return;
64
+ const now = Date.now();
65
+ const deltaSeconds = (now - this.lastUpdateTime) / 1000;
66
+ this.lastUpdateTime = now;
67
+ this.updateSimulation(deltaSeconds);
68
+ }, this.config.updateInterval);
69
+ }
70
+ updateSimulation(deltaSeconds) {
71
+ let stateChanged = false;
72
+ // Update temperature based on liquid state
73
+ if (this.state.liquidState !== LiquidState.Empty) {
74
+ const tempDiff = this.state.targetTemp - this.state.currentTemp;
75
+ const maxChange = this.config.tempChangeRate * deltaSeconds;
76
+ if (Math.abs(tempDiff) > 0.1) {
77
+ // Temperature is changing
78
+ const change = Math.sign(tempDiff) * Math.min(Math.abs(tempDiff), maxChange);
79
+ this.state.currentTemp = Math.round((this.state.currentTemp + change) * 100) / 100;
80
+ stateChanged = true;
81
+ // Update liquid state based on temperature direction
82
+ if (tempDiff > 0.5) {
83
+ if (this.state.liquidState !== LiquidState.Heating) {
84
+ this.state.liquidState = LiquidState.Heating;
85
+ }
86
+ }
87
+ else if (tempDiff < -0.5) {
88
+ if (this.state.liquidState !== LiquidState.Cooling) {
89
+ this.state.liquidState = LiquidState.Cooling;
90
+ }
91
+ }
92
+ }
93
+ else {
94
+ // Temperature is stable
95
+ if (this.state.liquidState !== LiquidState.StableTemperature) {
96
+ this.state.liquidState = LiquidState.StableTemperature;
97
+ stateChanged = true;
98
+ }
99
+ }
100
+ }
101
+ // Update battery
102
+ if (this.state.isCharging) {
103
+ // Charging
104
+ const chargeGain = (BATTERY_CHARGE_RATE / 60) * deltaSeconds;
105
+ this.state.batteryLevel = Math.min(100, this.state.batteryLevel + chargeGain);
106
+ stateChanged = true;
107
+ }
108
+ else if (this.state.liquidState === LiquidState.Heating) {
109
+ // Draining while heating
110
+ const drain = (BATTERY_DRAIN_RATE_HEATING / 60) * deltaSeconds;
111
+ this.state.batteryLevel = Math.max(0, this.state.batteryLevel - drain);
112
+ stateChanged = true;
113
+ }
114
+ else if (this.state.liquidState === LiquidState.StableTemperature) {
115
+ // Draining while maintaining
116
+ const drain = (BATTERY_DRAIN_RATE_MAINTAINING / 60) * deltaSeconds;
117
+ this.state.batteryLevel = Math.max(0, this.state.batteryLevel - drain);
118
+ stateChanged = true;
119
+ }
120
+ if (stateChanged) {
121
+ this.emitState();
122
+ }
123
+ }
124
+ async setTargetTemp(temp) {
125
+ const clampedTemp = Math.max(MIN_TEMP_CELSIUS, Math.min(MAX_TEMP_CELSIUS, temp));
126
+ this.state.targetTemp = clampedTemp;
127
+ this.emitState();
128
+ }
129
+ async setTemperatureUnit(unit) {
130
+ this.state.temperatureUnit = unit;
131
+ this.emitState();
132
+ }
133
+ async setLedColor(color) {
134
+ this.state.color = { ...color };
135
+ this.emitState();
136
+ }
137
+ getState() {
138
+ return { ...this.state };
139
+ }
140
+ emitState() {
141
+ this.emit('stateChange', this.getState());
142
+ }
143
+ async disconnect() {
144
+ if (this.simulationInterval) {
145
+ clearInterval(this.simulationInterval);
146
+ this.simulationInterval = null;
147
+ }
148
+ if (this.isConnected) {
149
+ this.isConnected = false;
150
+ this.state.connected = false;
151
+ this.emit('disconnected');
152
+ this.emitState();
153
+ }
154
+ }
155
+ // Mock-specific methods for testing scenarios
156
+ /** Simulate placing the mug on the charger */
157
+ simulateStartCharging() {
158
+ this.state.isCharging = true;
159
+ this.emitState();
160
+ }
161
+ /** Simulate removing the mug from the charger */
162
+ simulateStopCharging() {
163
+ this.state.isCharging = false;
164
+ this.emitState();
165
+ }
166
+ /** Simulate the mug becoming empty */
167
+ simulateEmpty() {
168
+ this.state.liquidState = LiquidState.Empty;
169
+ this.state.currentTemp = 0;
170
+ this.emitState();
171
+ }
172
+ /** Simulate filling the mug with liquid at a given temperature */
173
+ simulateFill(temperature) {
174
+ this.state.currentTemp = temperature;
175
+ this.state.liquidState = LiquidState.Filling;
176
+ this.emitState();
177
+ // Transition to appropriate state after a short delay
178
+ setTimeout(() => {
179
+ if (this.state.currentTemp < this.state.targetTemp) {
180
+ this.state.liquidState = LiquidState.Heating;
181
+ }
182
+ else if (this.state.currentTemp > this.state.targetTemp) {
183
+ this.state.liquidState = LiquidState.Cooling;
184
+ }
185
+ else {
186
+ this.state.liquidState = LiquidState.StableTemperature;
187
+ }
188
+ this.emitState();
189
+ }, 500);
190
+ }
191
+ /** Simulate a connection drop */
192
+ simulateDisconnect() {
193
+ this.disconnect();
194
+ }
195
+ /** Set battery level directly (for testing low battery scenarios) */
196
+ simulateBatteryLevel(level) {
197
+ this.state.batteryLevel = Math.max(0, Math.min(100, level));
198
+ this.emitState();
199
+ }
200
+ }
201
+ // Singleton instance for mock mode
202
+ let mockInstance = null;
203
+ export function getMockBluetoothManager(config) {
204
+ if (!mockInstance) {
205
+ mockInstance = new MockBluetoothManager(config);
206
+ }
207
+ return mockInstance;
208
+ }
209
+ export function resetMockBluetoothManager() {
210
+ if (mockInstance) {
211
+ mockInstance.disconnect();
212
+ mockInstance = null;
213
+ }
214
+ }
@@ -1,4 +1,4 @@
1
- import { AppSettings, Preset, TemperatureUnit } from './types.js';
1
+ import { AppSettings, Preset, TemperatureUnit } from "./types.js";
2
2
  export declare function getSettings(): AppSettings;
3
3
  export declare function getPresets(): Preset[];
4
4
  export declare function setPresets(presets: Preset[]): void;
@@ -1,10 +1,10 @@
1
- import Conf from 'conf';
2
- import { TemperatureUnit, DEFAULT_PRESETS, } from './types.js';
1
+ import Conf from "conf";
2
+ import { TemperatureUnit, DEFAULT_PRESETS, } from "./types.js";
3
3
  const config = new Conf({
4
- projectName: 'ember-mug-cli',
4
+ projectName: "ember-mug-cli",
5
5
  defaults: {
6
6
  presets: DEFAULT_PRESETS,
7
- temperatureUnit: TemperatureUnit.Celsius,
7
+ temperatureUnit: TemperatureUnit.Fahrenheit,
8
8
  notifyOnTemperatureReached: true,
9
9
  notifyAtBatteryPercentage: 15,
10
10
  lastTargetTemp: 55,
@@ -13,17 +13,17 @@ const config = new Conf({
13
13
  });
14
14
  export function getSettings() {
15
15
  return {
16
- presets: config.get('presets'),
17
- temperatureUnit: config.get('temperatureUnit'),
18
- notifyOnTemperatureReached: config.get('notifyOnTemperatureReached'),
19
- notifyAtBatteryPercentage: config.get('notifyAtBatteryPercentage'),
16
+ presets: config.get("presets"),
17
+ temperatureUnit: config.get("temperatureUnit"),
18
+ notifyOnTemperatureReached: config.get("notifyOnTemperatureReached"),
19
+ notifyAtBatteryPercentage: config.get("notifyAtBatteryPercentage"),
20
20
  };
21
21
  }
22
22
  export function getPresets() {
23
- return config.get('presets');
23
+ return config.get("presets");
24
24
  }
25
25
  export function setPresets(presets) {
26
- config.set('presets', presets);
26
+ config.set("presets", presets);
27
27
  }
28
28
  export function addPreset(preset) {
29
29
  const presets = getPresets();
@@ -39,34 +39,34 @@ export function updatePreset(id, updates) {
39
39
  setPresets(presets);
40
40
  }
41
41
  export function getTemperatureUnit() {
42
- return config.get('temperatureUnit');
42
+ return config.get("temperatureUnit");
43
43
  }
44
44
  export function setTemperatureUnit(unit) {
45
- config.set('temperatureUnit', unit);
45
+ config.set("temperatureUnit", unit);
46
46
  }
47
47
  export function getLastTargetTemp() {
48
- return config.get('lastTargetTemp');
48
+ return config.get("lastTargetTemp");
49
49
  }
50
50
  export function setLastTargetTemp(temp) {
51
- config.set('lastTargetTemp', temp);
51
+ config.set("lastTargetTemp", temp);
52
52
  }
53
53
  export function getLedColor() {
54
- return config.get('ledColor');
54
+ return config.get("ledColor");
55
55
  }
56
56
  export function setLedColor(color) {
57
- config.set('ledColor', color);
57
+ config.set("ledColor", color);
58
58
  }
59
59
  export function getNotifyOnTemperatureReached() {
60
- return config.get('notifyOnTemperatureReached');
60
+ return config.get("notifyOnTemperatureReached");
61
61
  }
62
62
  export function setNotifyOnTemperatureReached(enabled) {
63
- config.set('notifyOnTemperatureReached', enabled);
63
+ config.set("notifyOnTemperatureReached", enabled);
64
64
  }
65
65
  export function getNotifyAtBatteryPercentage() {
66
- return config.get('notifyAtBatteryPercentage');
66
+ return config.get("notifyAtBatteryPercentage");
67
67
  }
68
68
  export function setNotifyAtBatteryPercentage(percentage) {
69
- config.set('notifyAtBatteryPercentage', percentage);
69
+ config.set("notifyAtBatteryPercentage", percentage);
70
70
  }
71
71
  export function resetSettings() {
72
72
  config.clear();
@@ -0,0 +1,135 @@
1
+ import { LiquidState } from './types.js';
2
+ export interface Theme {
3
+ primary: string;
4
+ secondary: string;
5
+ text: string;
6
+ dimText: string;
7
+ name: string;
8
+ }
9
+ export declare const THEMES: {
10
+ readonly heating: {
11
+ readonly primary: "#FF6B35";
12
+ readonly secondary: "#FF8C5A";
13
+ readonly text: "white";
14
+ readonly dimText: "#FFD4C4";
15
+ readonly name: "Heating";
16
+ };
17
+ readonly cooling: {
18
+ readonly primary: "#FF6B35";
19
+ readonly secondary: "#FF8C5A";
20
+ readonly text: "white";
21
+ readonly dimText: "#FFD4C4";
22
+ readonly name: "Cooling";
23
+ };
24
+ readonly stable: {
25
+ readonly primary: "#4A90D9";
26
+ readonly secondary: "#6BA3E0";
27
+ readonly text: "white";
28
+ readonly dimText: "#B8D4F0";
29
+ readonly name: "Perfect";
30
+ };
31
+ readonly empty: {
32
+ readonly primary: "#666666";
33
+ readonly secondary: "#888888";
34
+ readonly text: "white";
35
+ readonly dimText: "#AAAAAA";
36
+ readonly name: "Empty";
37
+ };
38
+ readonly filling: {
39
+ readonly primary: "#4A90D9";
40
+ readonly secondary: "#6BA3E0";
41
+ readonly text: "white";
42
+ readonly dimText: "#B8D4F0";
43
+ readonly name: "Filling";
44
+ };
45
+ readonly disconnected: {
46
+ readonly primary: "#444444";
47
+ readonly secondary: "#666666";
48
+ readonly text: "white";
49
+ readonly dimText: "#999999";
50
+ readonly name: "Disconnected";
51
+ };
52
+ };
53
+ export declare const TERMINAL_COLORS: {
54
+ readonly heating: {
55
+ readonly primary: "yellow";
56
+ readonly secondary: "yellowBright";
57
+ readonly border: "yellow";
58
+ readonly text: "white";
59
+ readonly dimText: "gray";
60
+ };
61
+ readonly cooling: {
62
+ readonly primary: "yellow";
63
+ readonly secondary: "yellowBright";
64
+ readonly border: "yellow";
65
+ readonly text: "white";
66
+ readonly dimText: "gray";
67
+ };
68
+ readonly stable: {
69
+ readonly primary: "cyan";
70
+ readonly secondary: "cyanBright";
71
+ readonly border: "cyan";
72
+ readonly text: "white";
73
+ readonly dimText: "gray";
74
+ };
75
+ readonly empty: {
76
+ readonly primary: "gray";
77
+ readonly secondary: "white";
78
+ readonly border: "gray";
79
+ readonly text: "white";
80
+ readonly dimText: "gray";
81
+ };
82
+ readonly filling: {
83
+ readonly primary: "cyan";
84
+ readonly secondary: "cyanBright";
85
+ readonly border: "cyan";
86
+ readonly text: "white";
87
+ readonly dimText: "gray";
88
+ };
89
+ readonly disconnected: {
90
+ readonly primary: "gray";
91
+ readonly secondary: "white";
92
+ readonly border: "gray";
93
+ readonly text: "white";
94
+ readonly dimText: "gray";
95
+ };
96
+ };
97
+ export type ThemeKey = keyof typeof TERMINAL_COLORS;
98
+ export declare function getThemeForState(liquidState: LiquidState, connected: boolean): ThemeKey;
99
+ export declare function getTerminalTheme(themeKey: ThemeKey): {
100
+ readonly primary: "yellow";
101
+ readonly secondary: "yellowBright";
102
+ readonly border: "yellow";
103
+ readonly text: "white";
104
+ readonly dimText: "gray";
105
+ } | {
106
+ readonly primary: "yellow";
107
+ readonly secondary: "yellowBright";
108
+ readonly border: "yellow";
109
+ readonly text: "white";
110
+ readonly dimText: "gray";
111
+ } | {
112
+ readonly primary: "cyan";
113
+ readonly secondary: "cyanBright";
114
+ readonly border: "cyan";
115
+ readonly text: "white";
116
+ readonly dimText: "gray";
117
+ } | {
118
+ readonly primary: "gray";
119
+ readonly secondary: "white";
120
+ readonly border: "gray";
121
+ readonly text: "white";
122
+ readonly dimText: "gray";
123
+ } | {
124
+ readonly primary: "cyan";
125
+ readonly secondary: "cyanBright";
126
+ readonly border: "cyan";
127
+ readonly text: "white";
128
+ readonly dimText: "gray";
129
+ } | {
130
+ readonly primary: "gray";
131
+ readonly secondary: "white";
132
+ readonly border: "gray";
133
+ readonly text: "white";
134
+ readonly dimText: "gray";
135
+ };
@@ -0,0 +1,112 @@
1
+ import { LiquidState } from './types.js';
2
+ export const THEMES = {
3
+ heating: {
4
+ primary: '#FF6B35', // Orange
5
+ secondary: '#FF8C5A',
6
+ text: 'white',
7
+ dimText: '#FFD4C4',
8
+ name: 'Heating',
9
+ },
10
+ cooling: {
11
+ primary: '#FF6B35', // Orange (cooling down but not at temp yet)
12
+ secondary: '#FF8C5A',
13
+ text: 'white',
14
+ dimText: '#FFD4C4',
15
+ name: 'Cooling',
16
+ },
17
+ stable: {
18
+ primary: '#4A90D9', // Blue
19
+ secondary: '#6BA3E0',
20
+ text: 'white',
21
+ dimText: '#B8D4F0',
22
+ name: 'Perfect',
23
+ },
24
+ empty: {
25
+ primary: '#666666', // Grey
26
+ secondary: '#888888',
27
+ text: 'white',
28
+ dimText: '#AAAAAA',
29
+ name: 'Empty',
30
+ },
31
+ filling: {
32
+ primary: '#4A90D9', // Blue
33
+ secondary: '#6BA3E0',
34
+ text: 'white',
35
+ dimText: '#B8D4F0',
36
+ name: 'Filling',
37
+ },
38
+ disconnected: {
39
+ primary: '#444444',
40
+ secondary: '#666666',
41
+ text: 'white',
42
+ dimText: '#999999',
43
+ name: 'Disconnected',
44
+ },
45
+ };
46
+ // Terminal color mappings (closest ANSI colors)
47
+ export const TERMINAL_COLORS = {
48
+ heating: {
49
+ primary: 'yellow', // Closest to orange in terminal
50
+ secondary: 'yellowBright',
51
+ border: 'yellow',
52
+ text: 'white',
53
+ dimText: 'gray',
54
+ },
55
+ cooling: {
56
+ primary: 'yellow',
57
+ secondary: 'yellowBright',
58
+ border: 'yellow',
59
+ text: 'white',
60
+ dimText: 'gray',
61
+ },
62
+ stable: {
63
+ primary: 'cyan',
64
+ secondary: 'cyanBright',
65
+ border: 'cyan',
66
+ text: 'white',
67
+ dimText: 'gray',
68
+ },
69
+ empty: {
70
+ primary: 'gray',
71
+ secondary: 'white',
72
+ border: 'gray',
73
+ text: 'white',
74
+ dimText: 'gray',
75
+ },
76
+ filling: {
77
+ primary: 'cyan',
78
+ secondary: 'cyanBright',
79
+ border: 'cyan',
80
+ text: 'white',
81
+ dimText: 'gray',
82
+ },
83
+ disconnected: {
84
+ primary: 'gray',
85
+ secondary: 'white',
86
+ border: 'gray',
87
+ text: 'white',
88
+ dimText: 'gray',
89
+ },
90
+ };
91
+ export function getThemeForState(liquidState, connected) {
92
+ if (!connected) {
93
+ return 'disconnected';
94
+ }
95
+ switch (liquidState) {
96
+ case LiquidState.Empty:
97
+ return 'empty';
98
+ case LiquidState.Filling:
99
+ return 'filling';
100
+ case LiquidState.Heating:
101
+ return 'heating';
102
+ case LiquidState.Cooling:
103
+ return 'cooling';
104
+ case LiquidState.StableTemperature:
105
+ return 'stable';
106
+ default:
107
+ return 'empty';
108
+ }
109
+ }
110
+ export function getTerminalTheme(themeKey) {
111
+ return TERMINAL_COLORS[themeKey];
112
+ }
@@ -29,7 +29,6 @@ export interface RGBColor {
29
29
  export interface Preset {
30
30
  id: string;
31
31
  name: string;
32
- icon: string;
33
32
  temperature: number;
34
33
  }
35
34
  export interface AppSettings {
package/dist/lib/types.js CHANGED
@@ -12,20 +12,20 @@ export var TemperatureUnit;
12
12
  TemperatureUnit[TemperatureUnit["Fahrenheit"] = 1] = "Fahrenheit";
13
13
  })(TemperatureUnit || (TemperatureUnit = {}));
14
14
  export const DEFAULT_PRESETS = [
15
- { id: '1', name: 'Latte', icon: '☕', temperature: 52.0 },
16
- { id: '2', name: 'Coffee', icon: '🍵', temperature: 55.0 },
17
- { id: '3', name: 'Tea', icon: '🍃', temperature: 60.0 },
15
+ { id: "1", name: "Latte", temperature: 52.0 },
16
+ { id: "2", name: "Coffee", temperature: 55.56 },
17
+ { id: "3", name: "Tea", temperature: 60.0 },
18
18
  ];
19
- export const EMBER_SERVICE_UUID = 'fc543622236c4c948fa9944a3e5353fa';
19
+ export const EMBER_SERVICE_UUID = "fc543622236c4c948fa9944a3e5353fa";
20
20
  export const EMBER_CHARACTERISTICS = {
21
- MUG_NAME: 'fc540001236c4c948fa9944a3e5353fa',
22
- CURRENT_TEMP: 'fc540002236c4c948fa9944a3e5353fa',
23
- TARGET_TEMP: 'fc540003236c4c948fa9944a3e5353fa',
24
- TEMP_UNIT: 'fc540004236c4c948fa9944a3e5353fa',
25
- BATTERY: 'fc540007236c4c948fa9944a3e5353fa',
26
- LIQUID_STATE: 'fc540008236c4c948fa9944a3e5353fa',
27
- PUSH_EVENTS: 'fc540012236c4c948fa9944a3e5353fa',
28
- LED_COLOR: 'fc540014236c4c948fa9944a3e5353fa',
21
+ MUG_NAME: "fc540001236c4c948fa9944a3e5353fa",
22
+ CURRENT_TEMP: "fc540002236c4c948fa9944a3e5353fa",
23
+ TARGET_TEMP: "fc540003236c4c948fa9944a3e5353fa",
24
+ TEMP_UNIT: "fc540004236c4c948fa9944a3e5353fa",
25
+ BATTERY: "fc540007236c4c948fa9944a3e5353fa",
26
+ LIQUID_STATE: "fc540008236c4c948fa9944a3e5353fa",
27
+ PUSH_EVENTS: "fc540012236c4c948fa9944a3e5353fa",
28
+ LED_COLOR: "fc540014236c4c948fa9944a3e5353fa",
29
29
  };
30
30
  export const MIN_TEMP_CELSIUS = 50;
31
31
  export const MAX_TEMP_CELSIUS = 63;
@@ -1,15 +1,18 @@
1
- import { TemperatureUnit, LiquidState } from './types.js';
1
+ import { TemperatureUnit, LiquidState } from "./types.js";
2
2
  export declare function formatTemperature(temp: number, unit: TemperatureUnit): string;
3
3
  export declare function celsiusToFahrenheit(celsius: number): number;
4
4
  export declare function fahrenheitToCelsius(fahrenheit: number): number;
5
5
  export declare function formatBatteryLevel(level: number): string;
6
6
  export declare function getBatteryIcon(level: number, isCharging: boolean): string;
7
7
  export declare function getLiquidStateText(state: LiquidState): string;
8
- export declare function getLiquidStateIcon(state: LiquidState): string;
9
8
  export declare function clampTemperature(temp: number): number;
10
9
  export declare function formatDuration(minutes: number): string;
11
- export declare function estimateTimeToTargetTemp(currentTemp: number, targetTemp: number, liquidState: LiquidState): number | null;
12
- export declare function estimateBatteryLife(batteryLevel: number, isCharging: boolean, liquidState: LiquidState): number | null;
10
+ export declare function estimateTimeToTargetTemp(currentTemp: number, targetTemp: number, liquidState: LiquidState, dynamicRate?: number): number | null;
11
+ export declare function estimateBatteryLife(batteryLevel: number, isCharging: boolean, liquidState: LiquidState, dynamicRate?: number): number | null;
12
+ export declare function calculateRate(history: {
13
+ value: number;
14
+ time: number;
15
+ }[], windowMs?: number): number;
13
16
  export declare function getTemperatureColor(currentTemp: number, targetTemp: number): string;
14
17
  export declare function interpolateColor(value: number, minColor: [number, number, number], maxColor: [number, number, number]): [number, number, number];
15
18
  export declare function rgbToHex(r: number, g: number, b: number): string;