Open mblauser opened 1 month ago
Very cool!! Testing on my node here appears as below. I wonder if it would take up less space if we had it on the second row somewhere? "ch" seems to occasionally spill out of the div, but if we were to remove it, it would be difficult to distinguish between battery and ch util. Another consideration is whether or not to include it in "smallMode" (left arrow in UI).
I'm happy to take the pull when you are happy and we can adjust down the line as we see it in action.
I was playing around a little with a sidebar display of channel util. It can show percentage on mouseover. I'm flexible, just some ideas!
<!-- Channel Utilization % -->
{#if node.deviceMetrics?.channelUtilization}
<div
title="{(node.deviceMetrics?.channelUtilization).toFixed(0)}% Channel Utilization"
class="absolute w-1.5 rounded bottom-1 top-1 right-0.5 overflow-hidden border border-white/20 flex flex-col"
>
<div class="grow"></div>
<div class="bg-green-500" style="height: {(node.deviceMetrics?.channelUtilization).toFixed(0)}%;"></div>
</div>
{/if}
I like the concept of the vertical bar representation with mouse-over description. Organizationally I am hesitant to move the box to the 2nd row bc I believe it should remain grouped with SNR and RSSI. This vertical colorized bar should fit nicely in both smallMode and expanded mode.
Is this the proper way to introduce a local variable in JavaScript?
{let $thisNodeChUasINT = (node.deviceMetrics?.channelUtilization).toFixed(0);}
<div title="{$thisNodeChUasINT}% Channel Utilization" class=...>
Then we can colorize that vertical bar using these thresholds:
{$thisNodeChUasINT < 15 ? 'green' : $thisNodeChUasINT < 25 ? 'yellow' : 'red'}
Perhaps we should reduce the scale of the vertical bar to only show 0-50 instead of 0-100; or artificially double the visually displayed value. In practice, the bar will not ever come close to 100% as any mesh tends to fall apart above 40%; in which case seeing a solid red bar w 50 being the upper maximum representation makes sense.
Maybe later we can add into the settings user-defined thresholds for personal preference.
This is a reminder to myself to rewrite using Math.floor() [approx 4x faster operation] instead of toFixed(0)
Math.floor(node?.deviceMetrics?.channelUtilization)
within the CSS, I do not see a color definition for .bg-yellow-500 nor .bg-orange-500
I'd like to use these thresholds: under 15% = green under 25% = yellow under 35% = an attention-getting orange 35% and above = attention-getting red
do you have a recommendation for adding .bg-yellow-500 and .bg-orange-500?
Additionally, I've visually emphasized the 0-50% scale of the vertical bar. Any channelUtilization values over 50 will still represent 100% of the vertical bar.
I've updated the draft pull request with refactored code, but haven't yet been able to get the project compiled on my local macos workstation to test this code myself. Please test.
Unfortunately the #let
convention does not work in Svelte:
{#let channelUtilizationINT = Math.floor(node.deviceMetrics.channelUtilization)}
This problem would probably be best solved using a separate Svelte component. Example below as lib/ChannelUtilization.svelte
:
<script lang="ts">
import type { NodeInfo } from 'api/src/vars'
export let node: NodeInfo
let channelUtilizationINT = Math.floor(node.deviceMetrics?.channelUtilization || 0)
let scaledHeight = Math.min(channelUtilizationINT * 2, 100)
let colorClass = channelUtilizationINT < 15 ? 'green' : channelUtilizationINT < 25 ? 'yellow' : channelUtilizationINT < 35 ? 'orange' : 'red'
</script>
{#if node?.deviceMetrics?.channelUtilization}
<div
title="{channelUtilizationINT}% Observed Channel Utilization"
class="absolute w-1.5 rounded bottom-1 top-1 right-0.5 overflow-hidden border border-white/20 flex flex-col"
aria-label="Observed Channel Utilization: {channelUtilizationINT}%"
aria-valuemin="0"
aria-valuemax="50"
aria-valuenow={channelUtilizationINT}
>
<div class="grow"></div>
<div
class:bg-green-500={colorClass === 'green'}
class:bg-yellow-500={colorClass === 'yellow'}
class:bg-orange-500={colorClass === 'orange'}
class:bg-red-500={colorClass === 'red'}
style="height: {scaledHeight}%;"
></div>
</div>
{/if}
Then this component can be included in Nodes.svelte
:
<script>
import ChannelUtilization from './lib/ChannelUtilization.svelte'
</script>
...
<!-- Channel Utilization % -->
<ChannelUtilization {node} />
Also add a relative
class to line 85:
<div
class:ring-1={node.hopsAway == 0}
class="relative bg-blue-300/10 rounded px-1 py-0.5 flex flex-col gap-0.5 {node.num == $myNodeNum ? 'bg-gradient-to-r ' : ''} {Date.now() - node.lastHeard * 1000 < 3.6e6 ? '' : 'grayscale'}"
>
I artificially increased channel utilization in my local environment to test the colors and they look great!
I will find some time to update the README with some documentation on running the code locally as it is a bit unique in setup. Thanks!
Pushed Affirmatech:patch-2 with separate component code
I appreciate the explanation. Thank you. I agree w your suggestion of using a separate Svelte component; keeps it clean and reduces injected code in Nodes.svelte
Is it possible/advisable to instead use reactive declarations for these local variables within lib/ChannelUtilization.svelte?
<script lang="ts">
import type { NodeInfo } from 'api/src/vars';
export let node: NodeInfo;
$: channelUtilizationINT = node?.deviceMetrics?.channelUtilization
? Math.floor(node.deviceMetrics.channelUtilization)
: null;
$: scaledHeight = channelUtilizationINT !== null
? Math.min(channelUtilizationINT * 2, 100)
: 0;
$: colorClass = channelUtilizationINT !== null
? (channelUtilizationINT < 15 ? 'green' :
channelUtilizationINT < 25 ? 'yellow' :
channelUtilizationINT < 35 ? 'orange' :
'red')
: 'grayscale'; // default color when channelUtilizationINT is null
</script>
{#if channelUtilizationINT !== null}
<div
title="{channelUtilizationINT}% Observed Channel Utilization"
class="absolute w-1.5 rounded bottom-1 top-1 right-0.5 overflow-hidden border border-white/20 flex flex-col"
aria-label="Observed Channel Utilization: {channelUtilizationINT}%"
aria-valuemin="0"
aria-valuemax="50"
aria-valuenow={channelUtilizationINT}
>
<div class="grow"></div>
<div
class:bg-green-500={colorClass === 'green'}
class:bg-yellow-500={colorClass === 'yellow'}
class:bg-orange-500={colorClass === 'orange'}
class:bg-red-500={colorClass === 'red'}
class:grayscale={colorClass === 'grayscale'}
style="height: {scaledHeight}%;"
></div>
</div>
{/if}
Should we display an empty grayscale vertical bar when channelUtilization is not reported? It might look better aligned if additional vertical bars are added later. Please check the grayscale implementation above.
Would you please explain the intention of adding the suggested relative class:
<div
class:ring-1={node.hopsAway == 0}
class="relative bg-blue-300/10 rounded px-1 py-0.5 flex flex-col gap-0.5 {node.num == $myNodeNum ? 'bg-gradient-to-r ' : ''} {Date.now() - node.lastHeard * 1000 < 3.6e6 ? '' : 'grayscale'}"
>
Ah yes, I believe you are correct regarding the reactive declarations. Great catch!
Regarding relative
-- I was using absolute positioning to put the bar on the right side, but to keep it constrained within the node's box (and not the node list) a relative
was needed. After pondering it, this may not be the cleanest approach, however, as we need to manually pad space to make the bar fit.. Perhaps a parent flex
div would be more appropriate, but would need some experimentation.
I hope to have details on setting up local development soon. Real life has been busy lately, but hope to catch up with all this soon.
The README has been updated with setting up a local development environment. If you need any additional information just let me know. Thanks!
Thank you. I was successful setting up a dev environment on MacOS based on your README instructions. Have not found time yet to experiment with the UI/UX code.
Proposed Enhancement: will display reported channel utilization% (rounded to int) for each node. Placement to the right of any reported SNR and RSSI
Users may find each node's respective reported channel utilization useful in identifying problem areas on the mesh. For now, I think the best placement for this is to the right of any potential reported SNR and RSSI data. The box will only display if deviceMetrics?.channelUtilization exists, displaying only an INT value.
Eventually we could have a toggle in settings to display this or not. We could also later add a colorized bar below the value once defined thresholds have been set. (0-14 green, 15-24 yellow, 25+ red ?)
proposed rough illustration:
*** Please give feedback or correct the html class used here. I used w-10 but perhaps w-8 or some other value is more appropriate?