generated from homebridge/homebridge-plugin-template
-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
41fe1ca
commit e102809
Showing
20 changed files
with
727 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Publish to npm | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
publish: | ||
runs-on: ubuntu-latest | ||
if: "!contains(github.event.head_commit.message, 'skip ci')" | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 18 | ||
registry-url: https://registry.npmjs.org/ | ||
- run: npm ci | ||
- run: npm run lint | ||
- run: npm publish | ||
env: | ||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
<link href="css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous" /> | ||
<script src="js/bootstrap.min.js" crossorigin="anonymous"></script> | ||
|
||
<div id="main" data-bs-theme="dark"> | ||
<div class="card"> | ||
|
||
<div class="card-header" id="uiButtons"> | ||
<h5 class="mb-0 text-center"> | ||
<button class="btn btn-primary" data-bs-toggle="collapse" data-bs-target="#discoverDevices" | ||
aria-expanded="false" aria-controls="discoverDevices" style="border: 0;"> | ||
Discover devices | ||
</button> | ||
</h5> | ||
</div> | ||
|
||
<div class="collapse" id="discoverDevices"> | ||
<div class="card-body"> | ||
<form> | ||
<div class="mb-3" id="login"> | ||
<div class="mb-3"> | ||
<label for="username" class="form-label">Username</label> | ||
<input type="text" class="form-control" id="username"> | ||
</div> | ||
<div class="mb-3"> | ||
<label for="password" class="form-label">Password</label> | ||
<input type="password" class="form-control" id="password"> | ||
</div> | ||
<div class="mb-3"> | ||
<label for="region" class="form-label">Region</label> | ||
<select class="form-select" id="region"> | ||
<option value="Default (all other regions)">Default (all other regions)</option> | ||
<option value="Australia">Australia</option> | ||
<option value="China">China</option> | ||
<option value="Russia">Russia</option> | ||
<option value="USA">USA</option> | ||
</div> | ||
<button class="btn btn-primary btn-login" type="submit" id="discoverBtn" style="border: 0;"> | ||
Discover Devices on account | ||
</button> | ||
</form> | ||
<div class="text-center device-table" style="display: none" id="discoverTableWrapper"> | ||
<table class="table table-sm" id="discoverTable"> | ||
<thead> | ||
<tr> | ||
<th scope="col">Id</th> | ||
<th scope="col">Mac</th> | ||
<th scope="col">Account UUID</th> | ||
<th scope="col">Add / Update</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>No devices found!</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
</div> | ||
|
||
<style> | ||
|
||
.hide { | ||
display: none; | ||
} | ||
|
||
.disabled { | ||
pointer-events: none; | ||
opacity: 0.5; | ||
} | ||
</style> | ||
|
||
|
||
<script> | ||
|
||
(async () => { | ||
/********************************************************************* | ||
* Initialize Javascript supporting code | ||
*/ | ||
homebridge.showSpinner(); | ||
|
||
const { defaultConfig, defaultDeviceConfig } = await homebridge.request('/getDefaults'); | ||
const pluginConfig = await homebridge.getPluginConfig(); | ||
const configSchema = await homebridge.getPluginConfigSchema(); | ||
|
||
if (!pluginConfig.length) { | ||
pluginConfig.push({}); | ||
} | ||
let configuration = pluginConfig[0]; | ||
|
||
// Helper funcion to contol debug messages | ||
function debugLog(s) { | ||
if (configuration.uiDebug) { | ||
console.debug(s); | ||
} | ||
} | ||
|
||
debugLog(`Plugin Config:\n${JSON.stringify(configuration, null, 2)}`); | ||
configuration = await homebridge.request('/mergeToDefault', { config: configuration }); | ||
|
||
/********************************************************************* | ||
* showToast event listener | ||
* Provides information from server-side to the end user. | ||
*/ | ||
homebridge.addEventListener('showToast', (event) => { | ||
debugLog(`showToast Received: ${JSON.stringify(event.data)}`); | ||
if (event.data.success) { | ||
homebridge.toast.success(event.data.msg); | ||
} else { | ||
homebridge.toast.error(event.data.msg); | ||
} | ||
}); | ||
|
||
/********************************************************************* | ||
* filterOutDefaults | ||
* returns object for config.json that has default values removed | ||
*/ | ||
function filterOutDefaults(object, defaults) { | ||
|
||
function deleteEmptyObjects(object) { | ||
for (const [k, v] of Object.entries(object)) { | ||
if (!v || typeof v !== 'object' || v === null) { | ||
continue; | ||
} | ||
deleteEmptyObjects(v); | ||
if (Object.keys(v).length === 0) { | ||
delete object[k]; | ||
} | ||
} | ||
return object; | ||
} | ||
|
||
let newObject = {}; | ||
for (const [k, v] of Object.entries(object)) { | ||
if (k === 'devices') { | ||
newObject[k] = v.map((device) => { | ||
return filterOutDefaults(device, defaultDeviceConfig); | ||
}); | ||
} else if (typeof v === 'object' && v !== null) { | ||
newObject[k] = filterOutDefaults(v, defaults[k]); | ||
} else if (typeof defaults === 'object' && k in defaults && v === defaults[k]) { | ||
continue; | ||
} else { | ||
newObject[k] = v; | ||
} | ||
} | ||
return deleteEmptyObjects(newObject); | ||
} | ||
|
||
/********************************************************************* | ||
* createForm | ||
* Update the plugin config GUI. Does not save to config.json | ||
*/ | ||
function createForm(configSchema, configuration) { | ||
const configForm = homebridge.createForm(configSchema, configuration); | ||
configForm.onChange(async (changes) => { | ||
changes = filterOutDefaults(changes, defaultConfig); | ||
debugLog(`[createForm] Config changes:\n${JSON.stringify(changes, null, 2)}`); | ||
await homebridge.updatePluginConfig([changes]); | ||
}); | ||
} | ||
|
||
createForm(configSchema, configuration); | ||
homebridge.hideSpinner(); | ||
|
||
/********************************************************************* | ||
* Discover button clicked.... | ||
*/ | ||
document.getElementById('discoverBtn').addEventListener('click', async (e) => { | ||
e.preventDefault(); | ||
|
||
const username = document.getElementById('username').value; | ||
const password = document.getElementById('password').value; | ||
const region = document.getElementById('region').value; | ||
|
||
homebridge.showSpinner(); | ||
|
||
console.info(`Request login...`); | ||
try { | ||
const devices = await homebridge.request('/disover', { username, password, region }); | ||
debugLog(`Discovered devices:\n${JSON.stringify(devices, null, 2)}`); | ||
const table = document.getElementById('discoverTable').getElementsByTagName('tbody')[0]; | ||
table.innerHTML = ''; | ||
|
||
// Merge current config over to the server so discover has latest device config... | ||
let currentConfig = await homebridge.getPluginConfig(); | ||
currentConfig = currentConfig.length > 0 ? currentConfig[0] : {}; | ||
configuration = await homebridge.request('/mergeToDefault', { config: currentConfig }); | ||
|
||
currentConfig.devices = currentConfig.devices || []; | ||
if (devices) { | ||
|
||
const accountUuid = devices[0].name; | ||
|
||
configuration.username = username; | ||
configuration.password = password; | ||
configuration.region = region; | ||
configuration.accountUuid = accountUuid; | ||
|
||
const initialStates = await homebridge.request('/getInitialDeviceStates', { accountUuid, uuids: devices.map((d) => d.uuid) }); | ||
|
||
devices.forEach((device) => { | ||
const state = initialStates.find((s) => s.id === device.uuid); | ||
const tr = table.insertRow(); | ||
const td = tr.insertCell(); | ||
td.appendChild(document.createTextNode(device.uuid)); | ||
td.setAttribute('scope', 'row'); | ||
|
||
tr.insertCell().appendChild(document.createTextNode(device.mac)); | ||
tr.insertCell().appendChild(document.createTextNode(device.name)); | ||
|
||
const addCell = tr.insertCell(); | ||
if (currentConfig.devices.find((d) => d.id === device.uuid)) { | ||
addCell.appendChild(document.createTextNode('Already added')); | ||
} else { | ||
// No record for this device, add button to add it. | ||
const button = document.createElement('button'); | ||
button.innerText = 'Add'; | ||
button.className = 'btn btn-secondary btn-sm'; | ||
button.addEventListener('click', async () => { | ||
// Add button clicked... | ||
const newDevice = { | ||
id: device.uuid, | ||
name: state.name | ||
}; | ||
|
||
configuration.devices.push({ | ||
...defaultDeviceConfig, | ||
...newDevice | ||
}); | ||
debugLog(`Adding new device:\n${JSON.stringify({ ...defaultDeviceConfig, ...newDevice }, null, 2)}`); | ||
// refresh view | ||
createForm(configSchema, configuration); | ||
|
||
addCell.removeChild(button); | ||
addCell.appendChild(document.createTextNode('Added')); | ||
|
||
homebridge.toast.success('Device added'); | ||
}); | ||
addCell.appendChild(button); | ||
} | ||
}); | ||
} else { | ||
table.innerHTML += `<tr><td>No devices found!</td></tr>`; | ||
} | ||
document.getElementById('discoverTableWrapper').style.display = 'block'; | ||
|
||
homebridge.hideSpinner(); | ||
|
||
} catch (e) { | ||
homebridge.toast.error(e.message); | ||
homebridge.hideSpinner(); | ||
return; | ||
|
||
} | ||
|
||
}); | ||
})(); | ||
|
||
</script> |
Large diffs are not rendered by default.
Oops, something went wrong.
Oops, something went wrong.