Skip to content

Commit

Permalink
Merge pull request #4 from edger477/main
Browse files Browse the repository at this point in the history
UI support for power info and box name
  • Loading branch information
Onwrikbaar authored Nov 21, 2024
2 parents 5f9c289 + 911c35c commit 42d210b
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 41 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ jobs:
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact

- name: Upload Artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: './UI'
# Deploy UI folder
path: './UI/'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
33 changes: 10 additions & 23 deletions UI/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,15 @@ <h1>NeoDK control panel</h1>
</div>
</div>
<div v-for="device in devices" :key="device.id" class="my-3 container">
<h2 class="d-inline-block my-2" style="height: 60px;">
NeoDK ({{ device.state.PlayState }} | {{ device.state.Intensity }}% )</h2>
<p v-if="!device.changingName" class="h1 d-inline-block my-2" style="height: 60px;">
{{ device.Name || "(no name)"}}
| <button @click="device.changeName()" class="btn btn-primary mx-1">Change</button></p>
<p v-else class="h1 d-inline-block my-2" style="height: 60px;">
<input type="text" v-model="device.newName" placeholder="enter box name" />
<button @click="device.saveName()" class="btn btn-primary mx-1">Save</button></p>
</p>
<h3>({{ device.state.PlayState }} | {{ device.state.Intensity }}% )</h3>
<h6>Battery Voltage: {{ device.state.power.BatteryVoltage }}V</h6>
<div class="progress my-2" role="progressbar"
v-bind:aria-valuenow="parseInt(Math.round(device.state.Intensity))" aria-valuemin="0"
aria-valuemax="100" style="height: 3em">
Expand All @@ -54,26 +61,6 @@ <h2 class="d-inline-block my-2" style="height: 60px;">
<span class="h3"> {{ device.state.Intensity }} </span>
</div>
</div>
<!-- <div class="progress-stacked my-2" style="height: 1em">
<div class="progress" role="progressbar"
v-bind:aria-valuenow="parseInt(Math.round(device.vcap))" aria-valuemin="0"
aria-valuemax="1200" v-bind:style=" { width: parseInt(Math.round(device.vcap/120)) +'%' }">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-info">
</div>
</div>
<div class="progress" role="progressbar"
v-bind:aria-valuenow="parseInt(Math.round(device.vbat))" aria-valuemin="0"
aria-valuemax="1200"
v-bind:style=" { width: parseInt(Math.round((device.vbat - device.vcap)/120)) +'%' }">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-warning">
</div>
</div>
</div> -->
<!-- <div class="row my-2">
<div class="col">
Voltage: {{ device.vcap }} | {{ device.vbat }}
</div>
</div> -->
<div class="clearfix">&nbsp;</div>
<div class="row">
<div class="mx-2 col">
Expand Down Expand Up @@ -124,7 +111,7 @@ <h2 class="d-inline-block my-2" style="height: 60px;">
<legend class="danger">Pattern: {{ device.state.CurrentPattern }}
</legend>
<button v-for="pattern in device.state.AvailablePatterns"
@click="device.selectPattern(pattern)" class="btn btn-primary mx-2"
@click="device.selectPattern(pattern)" class="btn btn-primary mx-1 my-1"
v-bind:class="{ 'btn-success': (device.state.CurrentPattern == pattern) }">
{{ pattern }}
</button>
Expand Down
95 changes: 82 additions & 13 deletions UI/neodk.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class NeoDK {

this.logger = logger;
this.state = state;
this._name = '';
}

/**
Expand All @@ -41,17 +42,20 @@ class NeoDK {

// Public methods

get Name() {
return this._name;
}
set Name(value) {
this._name = value;
this.#writeString(value, NeoDK.#AttributeId.BoxName)
}
/**
* Method to select pattern to play
* @public
* @param {string} name name of the pattern to select
*/
selectPattern(name) {
let enc_name = new TextEncoder().encode(name);
const array = Array.from(enc_name); // Convert to regular array
array.unshift(NeoDK.#Encoding.UTF8_1Len, enc_name.length); // Use unshift
enc_name = Uint8Array.from(array);
this.#sendAttrWriteRequest(this.#the_writer, NeoDK.#AttributeId.CurrentPatternName, enc_name);
this.#writeString(name, NeoDK.#AttributeId.CurrentPatternName);
}

/**
Expand All @@ -60,11 +64,7 @@ class NeoDK {
* @param {ChangeStateCommand} state one of the accepted play states from ChangeStateCommand
*/
setPlayState(state) {
let enc_state = new TextEncoder().encode(state);
const array = Array.from(enc_state); // Convert to regular array
array.unshift(NeoDK.#Encoding.UTF8_1Len, enc_state.length); // Use unshift
enc_state = Uint8Array.from(array);
this.#sendAttrWriteRequest(this.#the_writer, NeoDK.#AttributeId.PlayPauseStop, enc_state);
this.#writeString(state, NeoDK.#AttributeId.PlayPauseStop);
}

/**
Expand All @@ -76,6 +76,10 @@ class NeoDK {
this.#sendAttrWriteRequest(this.#the_writer, NeoDK.#AttributeId.IntensityPercent, new Uint8Array([NeoDK.#Encoding.UnsignedInt1, intensity]));
}

refreshVoltages() {
this.#sendAttrReadRequest(this.#the_writer, NeoDK.#AttributeId.Voltages);
}

/**
* Method to get the port from browser
* User will be prompted to select a port that box is connected to
Expand All @@ -102,16 +106,49 @@ class NeoDK {
return await this.#usePort(port);
}

static BoxPower = class NeoDKBoxPower {
/**
*
*/
constructor() {
this._batteryVoltage = 0;
this._capacitorVoltage = 0;
this._primaryCurrent = 0;
}

get BatteryVoltage() {
return this._batteryVoltage;
}
set BatteryVoltage(value) {
this._batteryVoltage = value;
}

get CapacitorVoltage() {
return this._capacitorVoltage;
}
set CapacitorVoltage(value) {
this._capacitorVoltage = value;
}

get PrimaryCurrent() {
return this._primaryCurrent;
}
set PrimaryCurrent(value) {
this._primaryCurrent = value;
}

}

/**
* Structure that represents play state of NeoDK
*/
static State = class {
static State = class NeoDKState {
constructor() {
this._playState = NeoDK.#playStates[0];
this._intensity = 0;
this._currentPattern = '';
this._availablePatterns = [];
this.power = new NeoDK.BoxPower();
}


Expand Down Expand Up @@ -190,10 +227,12 @@ class NeoDK {
* @readonly
*/
static #AttributeId = {
Voltages: 3,
AllPatternNames: 5,
CurrentPatternName: 6,
IntensityPercent: 7,
PlayPauseStop: 8
PlayPauseStop: 8,
BoxName: 9
};

/**
Expand All @@ -205,6 +244,7 @@ class NeoDK {
static #Encoding = {
UnsignedInt1: 4,
UTF8_1Len: 12,
Bytes_1Len: 16,
Array: 22,
EndOfContainer: 24
}
Expand Down Expand Up @@ -248,6 +288,14 @@ class NeoDK {

// private methods

#writeString(value, attribute) {
let enc_value = new TextEncoder().encode(value);
const array = Array.from(enc_value); // Convert to regular array
array.unshift(NeoDK.#Encoding.UTF8_1Len, enc_value.length); // Use unshift
enc_value = Uint8Array.from(array);
this.#sendAttrWriteRequest(this.#the_writer, attribute, enc_value);
}

#initFrame(payload_size, frame_type, service_type, seq) {
const frame = new Uint8Array(NeoDK.#StructureSize.FrameHeader + payload_size);
frame[0] = (service_type << 4) | (frame_type << 1);
Expand Down Expand Up @@ -358,6 +406,17 @@ class NeoDK {
let offset = NeoDK.#StructureSize.AttributeAction;
const data_length = aa.length - offset;
switch (attribute_id) {
case NeoDK.#AttributeId.Voltages:
if (data_length >= 8 && aa[offset] == NeoDK.#Encoding.Bytes_1Len) {
const Vbat_mV = aa[offset + 2] | ((aa[offset + 3]) << 8);
const Vcap_mV = aa[offset + 4] | ((aa[offset + 5]) << 8);
const Ipri_mA = aa[offset + 6] | ((aa[offset + 7]) << 8);
this.state.power.BatteryVoltage = Vbat_mV / 1000;
this.state.power.CapacitorVoltage = Vcap_mV / 1000;
this.state.power.PrimaryCurrent = Ipri_mA / 1000;
this.logger.log('Vbat=' + Vbat_mV + ' mV, Vcap=' + Vcap_mV + ' mV, Ipri=' + Ipri_mA + ' mA');
}
break;
case NeoDK.#AttributeId.AllPatternNames:
if (data_length >= 2 && aa[offset] == NeoDK.#Encoding.Array) {
this.logger.log('Available patterns:');
Expand Down Expand Up @@ -386,6 +445,13 @@ class NeoDK {
this.logger.log('NeoDK is ' + NeoDK.#playStates[play_state]);
}
break;
case NeoDK.#AttributeId.BoxName:
if (aa[offset] == NeoDK.#Encoding.UTF8_1Len) {
const name = new TextDecoder().decode(aa.slice(offset + 2));
this._name = name;
this.logger.log('Box name is ' + name);
}
break;
default:
this.logger.log('Unexpected attribute id: ' + attribute_id);
}
Expand Down Expand Up @@ -484,6 +550,8 @@ class NeoDK {

// We have one readable attribute and three we can subscribe to.
this.#sendAttrReadRequest(this.#the_writer, NeoDK.#AttributeId.AllPatternNames);
this.#sendAttrReadRequest(this.#the_writer, NeoDK.#AttributeId.Voltages);
this.#sendAttrReadRequest(this.#the_writer, NeoDK.#AttributeId.BoxName);
this.#sendAttrSubscribeRequest(this.#the_writer, NeoDK.#AttributeId.CurrentPatternName);
this.#sendAttrSubscribeRequest(this.#the_writer, NeoDK.#AttributeId.IntensityPercent);
this.#sendAttrSubscribeRequest(this.#the_writer, NeoDK.#AttributeId.PlayPauseStop);
Expand Down Expand Up @@ -514,4 +582,5 @@ class NeoDK {
}
}

export default NeoDK;
export default NeoDK;

57 changes: 55 additions & 2 deletions UI/script.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import NeoDK from './neodk.js';
import { createApp, ref, toRaw, computed } from 'vue';

class NeoDKBoxPowerVM extends NeoDK.BoxPower {
constructor() {
super();

}

#batteryVoltage = ref(super._batteryVoltage);
#capacitorVoltage = ref(super._capacitorVoltage);
#primaryCurrent = ref(super._primaryCurrent);

get BatteryVoltage() {
return toRaw(this).#batteryVoltage.value;
}
set BatteryVoltage(value){
toRaw(this).#batteryVoltage.value = value;
}

get CapacitorVoltage() {
return toRaw(this).#capacitorVoltage.value;
}
set CapacitorVoltage(value){
toRaw(this).#capacitorVoltage.value = value;
}

get PrimaryCurrent() {
return toRaw(this).#primaryCurrent.value;
}
set PrimaryCurrent(value){
toRaw(this).#primaryCurrent.value = value;
}
}

class NeoDKStateVM extends NeoDK.State {
constructor() {
super();
this.power = new NeoDKBoxPowerVM();
}

#playState = ref(super._playState);
Expand Down Expand Up @@ -41,6 +74,16 @@ class NeoDKStateVM extends NeoDK.State {
}

class NeoDKVM extends NeoDK {

/**
*
*/
constructor(...args) {
super(...args);
this.changingName = ref(false);
this.newName = '';
}

setIntensity = (intensity) => super.setIntensity(intensity);

selectPattern = (pattern) => super.selectPattern(pattern);
Expand All @@ -52,6 +95,16 @@ class NeoDKVM extends NeoDK {
stop = () => super.setPlayState(NeoDK.ChangeStateCommand.stop);

paused = computed(() => ['paused', 'stopped'].includes(this.state.PlayState));

changeName = () => {
this.changingName.value = true;
this.newName = this.Name;
}

saveName = () => {
this.Name = this.newName;
this.changingName.value = false;
}
}

const app = createApp({
Expand All @@ -76,9 +129,9 @@ const app = createApp({
async refreshState() {
try {
this.devices.forEach(element => {
// todo add anything that needs to be periodically refreshed here
toRaw(element).refreshVoltages();
});
//setTimeout(this.refreshState, 1000);
setTimeout(this.refreshState, 1000 * 60 * 5);
} catch (error) {
console.error('Failed to fetch state', error);
}
Expand Down

0 comments on commit 42d210b

Please sign in to comment.