@mp-consulting/homebridge-daikin-cloud 1.3.7 โ 1.3.9
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.
|
@@ -1,34 +1,32 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html data-bs-theme="
|
|
2
|
+
<html lang="en" data-bs-theme="dark">
|
|
3
3
|
<head>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
7
|
-
document.documentElement.setAttribute('data-bs-theme', 'dark');
|
|
8
|
-
}
|
|
9
|
-
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
|
10
|
-
document.documentElement.setAttribute('data-bs-theme', e.matches ? 'dark' : 'light');
|
|
11
|
-
});
|
|
12
|
-
</script>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
13
6
|
<title>Daikin Cloud</title>
|
|
14
|
-
<link
|
|
7
|
+
<link rel="stylesheet" href="lib/kit.css">
|
|
15
8
|
<link rel="stylesheet" href="styles.css">
|
|
16
9
|
</head>
|
|
17
10
|
<body>
|
|
18
11
|
<div class="container-fluid p-3">
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
|
|
13
|
+
<!-- Header -->
|
|
14
|
+
<div class="mp-header mb-3">
|
|
15
|
+
<i class="bi bi-wind" style="color:#007DBB;"></i>
|
|
16
|
+
<div class="mp-header-text">
|
|
17
|
+
<div class="mp-header-title">Daikin Cloud</div>
|
|
18
|
+
<div class="mp-header-subtitle">Onecta integration for HomeKit</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="ms-auto d-flex align-items-center gap-2">
|
|
21
|
+
<span class="text-muted small" id="header-info">
|
|
22
|
+
<span id="token-expires-label" class="d-none">Expires in: </span>
|
|
23
|
+
<span id="token-expires" class="fw-medium"></span>
|
|
24
|
+
</span>
|
|
23
25
|
<span class="badge" id="status-badge">
|
|
24
26
|
<span class="status-dot" id="status-indicator"></span>
|
|
25
27
|
<span id="status-text">Checking...</span>
|
|
26
28
|
</span>
|
|
27
29
|
</div>
|
|
28
|
-
<div class="text-muted small" id="header-info">
|
|
29
|
-
<span id="token-expires-label" class="d-none">Token expires in: </span>
|
|
30
|
-
<span id="token-expires" class="fw-medium"></span>
|
|
31
|
-
</div>
|
|
32
30
|
</div>
|
|
33
31
|
|
|
34
32
|
<!-- Tab Navigation -->
|
|
@@ -71,7 +69,7 @@
|
|
|
71
69
|
</div>
|
|
72
70
|
<div id="devices-list" class="list-group"></div>
|
|
73
71
|
<div id="devices-empty" class="text-center py-5 d-none">
|
|
74
|
-
<
|
|
72
|
+
<i class="bi bi-phone fs-1 mb-2 opacity-50 d-block"></i>
|
|
75
73
|
<p class="mb-1">No devices found</p>
|
|
76
74
|
<p class="text-muted small">Make sure you're authenticated and your Daikin devices are set up in the Onecta app.</p>
|
|
77
75
|
</div>
|
|
@@ -389,7 +387,7 @@
|
|
|
389
387
|
|
|
390
388
|
<div id="auth-url-container" class="d-none mb-3">
|
|
391
389
|
<label class="form-label">Authorization URL:</label>
|
|
392
|
-
<div class="bg-
|
|
390
|
+
<div class="bg-body-secondary p-2 rounded border font-monospace small text-break" id="auth-url"></div>
|
|
393
391
|
<div class="form-text">If the button doesn't work, copy this URL manually.</div>
|
|
394
392
|
</div>
|
|
395
393
|
|
|
@@ -419,7 +417,7 @@
|
|
|
419
417
|
Manual entry (if automatic redirect fails)
|
|
420
418
|
</button>
|
|
421
419
|
</h2>
|
|
422
|
-
<div id="manual-callback-collapse" class="accordion-collapse collapse"
|
|
420
|
+
<div id="manual-callback-collapse" class="accordion-collapse collapse">
|
|
423
421
|
<div class="accordion-body">
|
|
424
422
|
<div class="alert alert-warning">
|
|
425
423
|
If you see an error page after login, copy the <strong>full URL</strong> from your browser's address bar and paste it below.
|
|
@@ -439,7 +437,9 @@
|
|
|
439
437
|
<!-- Step 3: Complete -->
|
|
440
438
|
<div class="wizard-content d-none" id="content-3">
|
|
441
439
|
<div class="text-center py-4">
|
|
442
|
-
<div class="bg-success text-white rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 64px; height: 64px; font-size: 32px;"
|
|
440
|
+
<div class="bg-success text-white rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 64px; height: 64px; font-size: 32px;">
|
|
441
|
+
<i class="bi bi-check-lg"></i>
|
|
442
|
+
</div>
|
|
443
443
|
<h5>Authentication Successful!</h5>
|
|
444
444
|
<p id="success-message" class="text-muted">Your Daikin Cloud account is now connected.</p>
|
|
445
445
|
</div>
|
|
@@ -507,6 +507,16 @@
|
|
|
507
507
|
</div>
|
|
508
508
|
</div>
|
|
509
509
|
</div>
|
|
510
|
+
|
|
511
|
+
<div class="mp-footer">
|
|
512
|
+
<a href="https://github.com/mp-consulting/homebridge-daikin-cloud" target="_blank" rel="noopener">
|
|
513
|
+
<i class="bi bi-github"></i>GitHub
|
|
514
|
+
</a>
|
|
515
|
+
<span class="mp-footer-sep">|</span>
|
|
516
|
+
<a href="https://www.npmjs.com/package/@mp-consulting/homebridge-daikin-cloud" target="_blank" rel="noopener">
|
|
517
|
+
<i class="bi bi-box-seam"></i>npm
|
|
518
|
+
</a>
|
|
519
|
+
</div>
|
|
510
520
|
</div>
|
|
511
521
|
|
|
512
522
|
<div class="loading-overlay d-none" id="loading">
|
|
@@ -517,7 +527,7 @@
|
|
|
517
527
|
|
|
518
528
|
<div id="global-error" class="toast-container position-fixed top-0 start-50 translate-middle-x p-3 d-none"></div>
|
|
519
529
|
|
|
520
|
-
<script src="
|
|
530
|
+
<script src="lib/kit.js"></script>
|
|
521
531
|
<script src="script.js"></script>
|
|
522
532
|
</body>
|
|
523
533
|
</html>
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/* @mp-consulting/homebridge-ui-kit v1.0.0 */
|
|
2
|
+
|
|
3
|
+
/* โโ Design tokens โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
4
|
+
CSS custom properties used throughout the design system.
|
|
5
|
+
Override these in your plugin's styles.css to customize per-plugin.
|
|
6
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
/* Brand */
|
|
10
|
+
--mp-primary: #4f46e5;
|
|
11
|
+
--mp-primary-rgb: 79, 70, 229;
|
|
12
|
+
--mp-primary-hover: #4338ca;
|
|
13
|
+
--mp-primary-subtle: rgba(79, 70, 229, 0.12);
|
|
14
|
+
|
|
15
|
+
/* Status */
|
|
16
|
+
--mp-status-online: #10b981;
|
|
17
|
+
--mp-status-online-glow: rgba(16, 185, 129, 0.35);
|
|
18
|
+
--mp-status-offline: #ef4444;
|
|
19
|
+
--mp-status-checking: #94a3b8;
|
|
20
|
+
|
|
21
|
+
/* Surfaces */
|
|
22
|
+
--mp-surface: rgba(255, 255, 255, 0.03);
|
|
23
|
+
--mp-border: rgba(255, 255, 255, 0.08);
|
|
24
|
+
|
|
25
|
+
/* Shape */
|
|
26
|
+
--mp-radius: 0.5rem;
|
|
27
|
+
--mp-shadow-hover: 0 0.5rem 1rem rgba(0, 0, 0, 0.3);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* โโ Bootstrap 5 overrides โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
31
|
+
Remap Bootstrap components to use brand tokens.
|
|
32
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
33
|
+
|
|
34
|
+
/* Primary button */
|
|
35
|
+
.btn-primary {
|
|
36
|
+
--bs-btn-bg: var(--mp-primary);
|
|
37
|
+
--bs-btn-border-color: var(--mp-primary);
|
|
38
|
+
--bs-btn-hover-bg: var(--mp-primary-hover);
|
|
39
|
+
--bs-btn-hover-border-color: var(--mp-primary-hover);
|
|
40
|
+
--bs-btn-active-bg: var(--mp-primary-hover);
|
|
41
|
+
--bs-btn-active-border-color: var(--mp-primary-hover);
|
|
42
|
+
--bs-btn-focus-shadow-rgb: var(--mp-primary-rgb);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Primary spinner */
|
|
46
|
+
.spinner-border.text-primary,
|
|
47
|
+
.spinner-grow.text-primary {
|
|
48
|
+
color: var(--mp-primary) !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* โโ Components โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
52
|
+
Reusable UI components used across all Homebridge plugins.
|
|
53
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
54
|
+
|
|
55
|
+
/* โโ Plugin header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
56
|
+
|
|
57
|
+
.mp-header {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 0.875rem;
|
|
61
|
+
margin-bottom: 0.5rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.mp-header-icon {
|
|
65
|
+
font-size: 2rem;
|
|
66
|
+
flex-shrink: 0;
|
|
67
|
+
line-height: 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.mp-header-title {
|
|
71
|
+
font-size: 1.375rem;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
margin: 0;
|
|
74
|
+
line-height: 1.3;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.mp-header-subtitle {
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
color: var(--bs-secondary-color);
|
|
80
|
+
margin: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* โโ Status indicator dot โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
84
|
+
|
|
85
|
+
.mp-status {
|
|
86
|
+
width: 8px;
|
|
87
|
+
height: 8px;
|
|
88
|
+
border-radius: 50%;
|
|
89
|
+
display: inline-block;
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
vertical-align: middle;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.mp-status-online {
|
|
95
|
+
background-color: var(--mp-status-online);
|
|
96
|
+
box-shadow: 0 0 5px var(--mp-status-online-glow);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.mp-status-offline {
|
|
100
|
+
background-color: var(--mp-status-offline);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.mp-status-checking {
|
|
104
|
+
background-color: var(--mp-status-checking);
|
|
105
|
+
animation: mp-pulse 1.5s ease-in-out infinite;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@keyframes mp-pulse {
|
|
109
|
+
0%, 100% { opacity: 1; }
|
|
110
|
+
50% { opacity: 0.35; }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* โโ Device card โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
114
|
+
|
|
115
|
+
.mp-device-card {
|
|
116
|
+
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.mp-device-card:hover {
|
|
121
|
+
transform: translateY(-1px);
|
|
122
|
+
box-shadow: var(--mp-shadow-hover) !important;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* โโ Settings surface card โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
126
|
+
|
|
127
|
+
.mp-settings-card {
|
|
128
|
+
background: var(--mp-surface);
|
|
129
|
+
border: 1px solid var(--mp-border) !important;
|
|
130
|
+
border-radius: var(--mp-radius);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* โโ Empty state โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
134
|
+
|
|
135
|
+
.mp-empty-state {
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
align-items: center;
|
|
139
|
+
justify-content: center;
|
|
140
|
+
padding: 3rem 1.5rem;
|
|
141
|
+
text-align: center;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.mp-empty-state-icon {
|
|
145
|
+
font-size: 2.5rem;
|
|
146
|
+
color: var(--bs-secondary-color);
|
|
147
|
+
margin-bottom: 0.75rem;
|
|
148
|
+
line-height: 1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.mp-empty-state-title {
|
|
152
|
+
font-size: 0.9375rem;
|
|
153
|
+
font-weight: 500;
|
|
154
|
+
color: var(--bs-secondary-color);
|
|
155
|
+
margin: 0 0 0.25rem;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.mp-empty-state-hint {
|
|
159
|
+
font-size: 0.8125rem;
|
|
160
|
+
color: var(--bs-secondary-color);
|
|
161
|
+
margin: 0;
|
|
162
|
+
opacity: 0.7;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* โโ Loading state โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
166
|
+
|
|
167
|
+
.mp-loading {
|
|
168
|
+
display: flex;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
align-items: center;
|
|
171
|
+
justify-content: center;
|
|
172
|
+
padding: 2.5rem 1.5rem;
|
|
173
|
+
gap: 0.75rem;
|
|
174
|
+
color: var(--bs-secondary-color);
|
|
175
|
+
font-size: 0.875rem;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* โโ Nav tabs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
179
|
+
|
|
180
|
+
.mp-tabs {
|
|
181
|
+
border-bottom: 1px solid var(--mp-border);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.mp-tabs .nav-link {
|
|
185
|
+
color: var(--bs-secondary-color);
|
|
186
|
+
border: none;
|
|
187
|
+
padding: 0.75rem 1.25rem;
|
|
188
|
+
font-weight: 500;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.mp-tabs .nav-link:hover {
|
|
192
|
+
color: var(--bs-body-color);
|
|
193
|
+
border: none;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.mp-tabs .nav-link.active {
|
|
197
|
+
color: var(--mp-primary);
|
|
198
|
+
background: transparent;
|
|
199
|
+
border: none;
|
|
200
|
+
border-bottom: 2px solid var(--mp-primary);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* โโ Metadata label โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
204
|
+
|
|
205
|
+
.mp-label {
|
|
206
|
+
font-size: 0.75rem;
|
|
207
|
+
text-transform: uppercase;
|
|
208
|
+
letter-spacing: 0.5px;
|
|
209
|
+
color: var(--bs-secondary-color);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* โโ View toggling โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
213
|
+
|
|
214
|
+
.mp-view {
|
|
215
|
+
display: none;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.mp-view.active {
|
|
219
|
+
display: block;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* โโ Support footer โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
223
|
+
|
|
224
|
+
.mp-footer {
|
|
225
|
+
display: flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
flex-wrap: wrap;
|
|
229
|
+
gap: 0.75rem 1rem;
|
|
230
|
+
padding-top: 1.5rem;
|
|
231
|
+
margin-top: 2rem;
|
|
232
|
+
border-top: 1px solid var(--mp-border);
|
|
233
|
+
font-size: 0.8125rem;
|
|
234
|
+
color: var(--bs-secondary-color);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.mp-footer a {
|
|
238
|
+
color: var(--bs-secondary-color);
|
|
239
|
+
text-decoration: none;
|
|
240
|
+
display: inline-flex;
|
|
241
|
+
align-items: center;
|
|
242
|
+
gap: 0.3rem;
|
|
243
|
+
transition: color 0.15s ease;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.mp-footer a:hover {
|
|
247
|
+
color: var(--mp-primary);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.mp-footer-sep {
|
|
251
|
+
color: var(--mp-border);
|
|
252
|
+
user-select: none;
|
|
253
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* @mp-consulting/homebridge-ui-kit v1.0.0
|
|
2
|
+
Brand design system for Homebridge plugins
|
|
3
|
+
https://github.com/mp-consulting/homebridge-ui-kit */
|
|
4
|
+
|
|
5
|
+
(function (global) {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
var MpKit = {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* StatusBadge โ returns inline HTML for device status badges.
|
|
12
|
+
*
|
|
13
|
+
* MpKit.StatusBadge.online() โ green dot + "Online"
|
|
14
|
+
* MpKit.StatusBadge.offline() โ red dot + "Offline"
|
|
15
|
+
* MpKit.StatusBadge.checking() โ animated dot + "Checking..."
|
|
16
|
+
* MpKit.StatusBadge.disabled() โ grey badge + "Disabled"
|
|
17
|
+
*/
|
|
18
|
+
StatusBadge: {
|
|
19
|
+
online: function (label) {
|
|
20
|
+
label = label || 'Online';
|
|
21
|
+
return '<span class="badge bg-success-subtle text-success">'
|
|
22
|
+
+ '<span class="mp-status mp-status-online me-1"></span>'
|
|
23
|
+
+ label + '</span>';
|
|
24
|
+
},
|
|
25
|
+
offline: function (label) {
|
|
26
|
+
label = label || 'Offline';
|
|
27
|
+
return '<span class="badge bg-danger-subtle text-danger">'
|
|
28
|
+
+ '<span class="mp-status mp-status-offline me-1"></span>'
|
|
29
|
+
+ label + '</span>';
|
|
30
|
+
},
|
|
31
|
+
checking: function (label) {
|
|
32
|
+
label = label || 'Checking...';
|
|
33
|
+
return '<span class="badge bg-secondary-subtle text-secondary">'
|
|
34
|
+
+ '<span class="mp-status mp-status-checking me-1"></span>'
|
|
35
|
+
+ label + '</span>';
|
|
36
|
+
},
|
|
37
|
+
disabled: function (label) {
|
|
38
|
+
label = label || 'Disabled';
|
|
39
|
+
return '<span class="badge bg-secondary">' + label + '</span>';
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* EmptyState โ returns HTML for an empty list placeholder.
|
|
45
|
+
*
|
|
46
|
+
* MpKit.EmptyState.render({
|
|
47
|
+
* iconClass: 'bi bi-lightbulb',
|
|
48
|
+
* title: 'No devices found',
|
|
49
|
+
* hint: 'Click Discover to scan your network',
|
|
50
|
+
* })
|
|
51
|
+
*/
|
|
52
|
+
EmptyState: {
|
|
53
|
+
render: function (opts) {
|
|
54
|
+
opts = opts || {};
|
|
55
|
+
var icon = opts.iconClass || 'bi bi-inbox';
|
|
56
|
+
var title = opts.title || 'No items';
|
|
57
|
+
var hint = opts.hint || '';
|
|
58
|
+
return '<div class="mp-empty-state">'
|
|
59
|
+
+ '<i class="' + icon + ' mp-empty-state-icon"></i>'
|
|
60
|
+
+ '<p class="mp-empty-state-title">' + title + '</p>'
|
|
61
|
+
+ (hint ? '<p class="mp-empty-state-hint">' + hint + '</p>' : '')
|
|
62
|
+
+ '</div>';
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Loading โ returns HTML for a centred loading spinner with message.
|
|
68
|
+
*
|
|
69
|
+
* MpKit.Loading.render('Loading device information...')
|
|
70
|
+
*/
|
|
71
|
+
Loading: {
|
|
72
|
+
render: function (message) {
|
|
73
|
+
message = message || 'Loading...';
|
|
74
|
+
return '<div class="mp-loading">'
|
|
75
|
+
+ '<div class="spinner-border spinner-border-sm text-secondary" role="status" aria-hidden="true"></div>'
|
|
76
|
+
+ '<span>' + message + '</span>'
|
|
77
|
+
+ '</div>';
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* View โ controls which .mp-view element is visible.
|
|
83
|
+
*
|
|
84
|
+
* MpKit.View.show('listView') โ shows #listView, hides all others
|
|
85
|
+
* MpKit.View.show('settingsView') โ shows #settingsView, hides all others
|
|
86
|
+
*/
|
|
87
|
+
View: {
|
|
88
|
+
show: function (id) {
|
|
89
|
+
document.querySelectorAll('.mp-view').forEach(function (v) {
|
|
90
|
+
v.classList.remove('active');
|
|
91
|
+
});
|
|
92
|
+
var el = document.getElementById(id);
|
|
93
|
+
if (el) { el.classList.add('active'); }
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Footer โ renders support links into a .mp-footer element.
|
|
99
|
+
*
|
|
100
|
+
* MpKit.Footer.render({
|
|
101
|
+
* github: 'https://github.com/mp-consulting/homebridge-...',
|
|
102
|
+
* npm: 'https://www.npmjs.com/package/@mp-consulting/...',
|
|
103
|
+
* changelog: 'https://github.com/.../blob/main/CHANGELOG.md',
|
|
104
|
+
* })
|
|
105
|
+
*/
|
|
106
|
+
Footer: {
|
|
107
|
+
render: function (opts) {
|
|
108
|
+
opts = opts || {};
|
|
109
|
+
var target = opts.target || '.mp-footer';
|
|
110
|
+
var el = typeof target === 'string' ? document.querySelector(target) : target;
|
|
111
|
+
if (!el) { return; }
|
|
112
|
+
var links = [];
|
|
113
|
+
if (opts.github) {
|
|
114
|
+
links.push('<a href="' + opts.github + '" target="_blank" rel="noopener">'
|
|
115
|
+
+ '<i class="bi bi-github"></i>GitHub</a>');
|
|
116
|
+
}
|
|
117
|
+
if (opts.npm) {
|
|
118
|
+
links.push('<a href="' + opts.npm + '" target="_blank" rel="noopener">'
|
|
119
|
+
+ '<i class="bi bi-box-seam"></i>npm</a>');
|
|
120
|
+
}
|
|
121
|
+
if (opts.changelog) {
|
|
122
|
+
links.push('<a href="' + opts.changelog + '" target="_blank" rel="noopener">'
|
|
123
|
+
+ '<i class="bi bi-clock-history"></i>Changelog</a>');
|
|
124
|
+
}
|
|
125
|
+
el.innerHTML = links.join('<span class="mp-footer-sep">|</span>');
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
global.MpKit = MpKit;
|
|
132
|
+
|
|
133
|
+
})(window);
|
|
@@ -825,7 +825,7 @@ const Devices = {
|
|
|
825
825
|
handleError(result) {
|
|
826
826
|
if (result.message?.includes('Not authenticated')) {
|
|
827
827
|
El.devicesEmpty.innerHTML = `
|
|
828
|
-
<
|
|
828
|
+
<i class="bi bi-lock fs-1 mb-2 opacity-50 d-block text-center"></i>
|
|
829
829
|
<p class="mb-1">Please authenticate first</p>
|
|
830
830
|
<p class="text-muted small">Go to Authentication tab to connect.</p>`;
|
|
831
831
|
DOM.show(El.devicesEmpty);
|
|
@@ -840,25 +840,25 @@ const Devices = {
|
|
|
840
840
|
const powerOn = device.powerState === 'on';
|
|
841
841
|
const mode = device.operationMode ? Utils.capitalize(device.operationMode) : '-';
|
|
842
842
|
const features = device.features?.length
|
|
843
|
-
?
|
|
843
|
+
? device.features.map(f => `<span class="badge bg-secondary bg-opacity-50 me-1">${f}</span>`).join('')
|
|
844
844
|
: '';
|
|
845
845
|
|
|
846
|
+
const meta = [
|
|
847
|
+
device.roomTemp ? `<span class="device-meta-item">Room: <span class="text-body-secondary">${Utils.escapeHtml(device.roomTemp)}</span></span>` : '',
|
|
848
|
+
device.outdoorTemp ? `<span class="device-meta-item">Outdoor: <span class="text-body-secondary">${Utils.escapeHtml(device.outdoorTemp)}</span></span>` : '',
|
|
849
|
+
`<span class="device-meta-item">Mode: <span class="text-body-secondary">${Utils.escapeHtml(mode)}</span></span>`,
|
|
850
|
+
`<span class="device-meta-item">Model: <span class="text-body-secondary">${Utils.escapeHtml(device.model)}</span></span>`,
|
|
851
|
+
].filter(Boolean).join('<span class="device-meta-sep">ยท</span>');
|
|
852
|
+
|
|
846
853
|
return `
|
|
847
854
|
<div class="list-group-item">
|
|
848
|
-
<div class="d-flex
|
|
849
|
-
<
|
|
850
|
-
<
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
</div>
|
|
854
|
-
</div>
|
|
855
|
-
<div class="d-flex flex-wrap gap-3 small text-muted">
|
|
856
|
-
${device.roomTemp ? `<span><strong>Room:</strong> ${Utils.escapeHtml(device.roomTemp)}</span>` : ''}
|
|
857
|
-
${device.outdoorTemp ? `<span><strong>Outdoor:</strong> ${Utils.escapeHtml(device.outdoorTemp)}</span>` : ''}
|
|
858
|
-
<span><strong>Mode:</strong> ${Utils.escapeHtml(mode)}</span>
|
|
859
|
-
<span><strong>Model:</strong> ${Utils.escapeHtml(device.model)}</span>
|
|
855
|
+
<div class="d-flex align-items-center">
|
|
856
|
+
<span class="device-power ${powerOn ? 'power-on' : 'power-off'} me-2">${powerOn ? 'ON' : 'OFF'}</span>
|
|
857
|
+
<span class="fw-semibold">${Utils.escapeHtml(device.name)}</span>
|
|
858
|
+
${features ? `<div class="ms-2">${features}</div>` : ''}
|
|
859
|
+
<span class="device-status ${online ? 'online' : 'offline'} ms-auto">${online ? 'Online' : 'Offline'}</span>
|
|
860
860
|
</div>
|
|
861
|
-
|
|
861
|
+
<div class="device-meta mt-1">${meta}</div>
|
|
862
862
|
</div>`;
|
|
863
863
|
},
|
|
864
864
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Daikin Cloud Homebridge UI - Custom Styles
|
|
3
|
-
* Bootstrap 5 is injected by Homebridge UI, these are plugin-specific overrides
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
/* Status Badge */
|
|
@@ -106,6 +105,18 @@
|
|
|
106
105
|
color: var(--bs-danger-text-emphasis);
|
|
107
106
|
}
|
|
108
107
|
|
|
108
|
+
/* Device meta row */
|
|
109
|
+
.device-meta {
|
|
110
|
+
font-size: 0.75rem;
|
|
111
|
+
color: var(--bs-tertiary-color);
|
|
112
|
+
opacity: 0.55;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.device-meta-sep {
|
|
116
|
+
margin: 0 0.4rem;
|
|
117
|
+
opacity: 0.4;
|
|
118
|
+
}
|
|
119
|
+
|
|
109
120
|
/* Device Toggle Labels */
|
|
110
121
|
.device-toggle-label.visible {
|
|
111
122
|
color: var(--bs-success);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"displayName": "Daikin Cloud",
|
|
3
3
|
"platformname": "daikincloud",
|
|
4
4
|
"name": "@mp-consulting/homebridge-daikin-cloud",
|
|
5
|
-
"version": "1.3.
|
|
5
|
+
"version": "1.3.9",
|
|
6
6
|
"description": "Integrate with the Daikin Cloud to control your Daikin air conditioning via the cloud",
|
|
7
7
|
"license": "(Apache-2.0 AND MIT)",
|
|
8
8
|
"repository": {
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"test:coverage": "vitest run --coverage",
|
|
26
26
|
"lint": "eslint . --max-warnings=0",
|
|
27
27
|
"watch": "npm run build && npm link && nodemon",
|
|
28
|
-
"
|
|
28
|
+
"copy:ui-kit": "mkdir -p homebridge-ui/public/lib && cp node_modules/@mp-consulting/homebridge-ui-kit/dist/kit.css homebridge-ui/public/lib/ && cp node_modules/@mp-consulting/homebridge-ui-kit/dist/kit.js homebridge-ui/public/lib/",
|
|
29
|
+
"build": "npm run copy:ui-kit && rimraf ./dist && tsc",
|
|
29
30
|
"prepublishOnly": "npm run lint && npm run build",
|
|
30
31
|
"release": "npm publish",
|
|
31
32
|
"release:beta": "npm publish --tag beta"
|
|
@@ -40,13 +41,14 @@
|
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@eslint/js": "^9.39.2",
|
|
44
|
+
"@mp-consulting/homebridge-ui-kit": "^1.0.0",
|
|
43
45
|
"@types/node": "^24.0.0",
|
|
44
46
|
"@types/ws": "^8.18.1",
|
|
45
47
|
"@vitest/coverage-v8": "^4.0.18",
|
|
46
48
|
"eslint": "^9.39.2",
|
|
47
49
|
"hap-nodejs": "^1.1.0",
|
|
48
50
|
"homebridge": "^2.0.0-beta.55",
|
|
49
|
-
"homebridge-config-ui-x": "^5.
|
|
51
|
+
"homebridge-config-ui-x": "^5.19.0",
|
|
50
52
|
"nodemon": "^3.1.11",
|
|
51
53
|
"rimraf": "^6.1.0",
|
|
52
54
|
"typescript": "^5.9.3",
|