[APP][Pro] Dashboard Studio - A completely free-form dashboard designer

I also noticed the slider issue @Amersfoort mentions. For me the slider sits on the edge of a container, I now gave it the same color as the edge…

For the calendar: The things I tried seem to work fine. The only issue I found so far is that it’s either icons or no icons.

  • If you disable the function in the configuration it shows no icons…(Gee, that’s strange :wink: )
  • If you enable it, but you empty the standard ph-calendar field, it still shows the standard calendar. In my opinion, one should be able to only show icons for specific ‘items’ (based on criteria, or text-content,…) without always having an icon.

This is just nitpicking, I know. For now I prefer my own (Claude/Grok) script for the Markdown. I’ll share with you below for inspiration.

Thanks for all the effort !

const jsonInput = args[0];
if (!jsonInput) { log(‘Geen argument ontvangen.’); return; }

let data;
try {
data = JSON.parse(jsonInput);
} catch (e) {
log(‘Ongeldige JSON:’, e.message); return;
}

const TZ = ‘Europe/Brussels’;
const IND = ’    ';   // 4 non-breaking spaces via HTML

function lokaalDagSleutel(isoString) {
const d = new Date(isoString);
const parts = new Intl.DateTimeFormat(‘nl-BE’, {
timeZone: TZ, year: ‘numeric’, month: ‘2-digit’, day: ‘2-digit’
}).formatToParts(d);
const get = type => parts.find(p => p.type === type).value;
return ${get('year')}-${get('month')}-${get('day')};
}

function tijdLabel(isoString) {
const d = new Date(isoString);
return new Intl.DateTimeFormat(‘nl-BE’, {
timeZone: TZ, hour: ‘2-digit’, minute: ‘2-digit’, hour12: false
}).format(d);
}

// Vandaag en morgen
const nuSleutel = lokaalDagSleutel(new Date().toISOString());
const [y, m, d] = nuSleutel.split(‘-’).map(Number);
const morgenDate = new Date(y, m - 1, d + 1);
const morgenSleutel = ${morgenDate.getFullYear()}-${String(morgenDate.getMonth()+1).padStart(2,'0')}-${String(morgenDate.getDate()).padStart(2,'0')};

const perDag = { [nuSleutel]: 
, [morgenSleutel]: 
 };

for (const event of data.events) {
const sleutel = lokaalDagSleutel(event.startDate);
if (perDag[sleutel] !== undefined) {
perDag[sleutel].push(event);
}
}

// Dedupliceren + sorteren
for (const sleutel of [nuSleutel, morgenSleutel]) {
const gezien = new Set();
perDag[sleutel] = perDag[sleutel].filter(event => {
const key = event.uid ? event.uid :
((event.isAllDay || event.multiDayAllDay || event.allDay) ? event.title : ${event.title}|${event.startDate});
if (gezien.has(key)) return false;
gezien.add(key);
return true;
});

perDag[sleutel].sort((a, b) => {
const rang = e => e.multiDayAllDay ? 0 : (e.isAllDay || e.allDay) ? 1 : 2;
if (rang(a) !== rang(b)) return rang(a) - rang(b);
return new Date(a.startDate) - new Date(b.startDate);
});
}

// Bouw Markdown
let md = ‘’;

for (const [sleutel, label] of [[nuSleutel, ‘Vandaag’], [morgenSleutel, ‘Morgen’]]) {
const events = perDag[sleutel];
md += ## ${label}\n\n;

if (events.length === 0) {
md += ${IND}geen afspraken\n\n;
} else {
for (const event of events) {
if (event.isAllDay || event.multiDayAllDay || event.allDay) {
md += ${IND}:ph-calendar-blank: *${event.title}*\n;
} else {
const van = tijdLabel(event.startDate);
md += ${IND}**${van}** ${event.title}\n;
}
}
md += ‘\n’;
}
}

log(md);
await tag(‘Agenda Markdown’, md);
log(‘Klaar!’);

I might have missed this but it can not find it. It would be nice to be able to change the font size for names in the light grid.

Also, when I have a light that does not support colours, I check the Override Master and remove all colours. But when I save and reload they are back. It does work and don’t show when live as expected, but in the settings I still can see the colours.

New V1.8.5 TEST version:

  • Fixed: Sliders and gauges can now fully hide their track or fill when you set the size to 0.
  • Improved: Calendar all‑day events now display with the correct end date (no extra day).
  • New: Calendar setting to wrap events in colored blocks, or keep them as plain lines.
  • New: Calendar setting to disable group timed event labels for time of day (Night/Morning/Afternoon/Evening).
  • New: Added four new theme “marker tint” colors for clearer categories and accents.
  • New: Text widget now supports simple callout blocks you can use in your content (4 color styles).
  • New: Text widget editor adds a quick “block callout” tool to wrap selected text.
  • Improved: Text widget tables now support Markdown alignment markers like :—: and —:.
  • Improved: Text markdown formatting reference updated in the help file.

I’ve made a lot of improvements to the calendar decoding and markdown conversion. I also added block colors to help distinguish between single-day, all-day, multi-day, and recurring events.

These colors are pulled from four new “marker” theme colors. I added these because I realized I didn’t have enough contrasting colors that actually matched the theme. Most of the existing colors were just different tints of the same shade.

If you’re using an older theme, it’s probably best to update these in the “theme colors” section first. You can also set them individually within the text widget.

If you’d prefer only the timed events to have a unique color, you can just set the other categories to the same color. And if you don’t want to use these new “Block cards” at all you can disable this in the Homey Dashboard studio Calendar configuration:

I have added an option to disable just the default icon. Another option is to disable the time of day labels in the day / week view. Also fixed a bug that it did not allow an empty list of binded icons:

Fixed this. Well, you have to set the thickness to 0 to hide it. (Always wondered how you did that rainbow gradient :sweat_smile: )

Tried the code, did not work at my end, fixed some smart quote conversion errors but got a json error. I have changed the json that is generated by the “Load & filter iCal” card. I needed to change some things in it, so I am afraid I broke your script :grimacing:

This is supported now in the Markdown text. :+1:

Thanks for the testing Bert and Amersfoort.

It is not there. I still need to overhaul this widget to match the newer style. Ill add font settings for every feature.

Hmmm I can’t seem to reproduce this problem.
I did:

  • Reset the canvas
  • added a light grid
  • Checked the override master
  • removed all the color presets
  • saved the dashboard
  • loaded the dashboard again
  • Settings are still like expected

What version of Dashboard studio are you running? (I tested with the latest Test version 1.8.5)

Am I allowed to nitpick some more?

The load & filter still works flawlessly over here, it didn’t even break the script on my side…strange.

I like the new ‘blocks’ a lot. I did not find a way yet to ‘filter’ events => colors based on the calendar they come from. As I’m merging 3 calendars, It 'd be nice to folow the color-scheme I have in Google Calendar… develop-idea :wink:

For the icons, thanks for the improvements… however a new issue pops up now: With the icon in front of the time, the time of these events is now misaligned with other times… I don’t know if changing the order (time - icon - text) is an option?

For the lay-out of the colums…am I mising something?

The bottom half of the screenshot below is my own script, which still works… but ofcourse hasn’t been updated yet with the new blocks and hasn’t got any icon-based integration…

I also sent you another beer (or coffee) as appreciation for all your work!

update: if you fool around with the opacity of the block-text, the icon is not playing along :wink:

I found another issue with the import of the ICS files.
I have recurrent items which return weekly on tuesday and wednesday. For next week these have been cancelled in the Google Agenda, but the Dashboard Studio still shows them.

Grok says its a common issue for basic calendar exports to miss these ‘exceptions’. I don’t know if this is something you can resolve…

:smiling_face:

Yes, please! I’m actually really happy with your feedback because I don’t use calendars as intensively as you do.

Ah, good idea. This is possible (I have to change the output json again to include the origin of the data). But you will loose the visual separation of the day events - timed events etc. I can not also add more then 4 separate blocks.

Also good suggestion

Hmmm I did not encounter this top aligning problem myself. I shall investigate this.

Thanks Bert! Appreciate it :clinking_beer_mugs:

Yes, I learned that Apple and Google also put a lot of special non-standard rules in those iCal files. I shall investigate if the filter can support the important ones.

If you just include a sort of ID in the JSON output, it’s enough. People can build their own Markdown-output if they don’t agree with your markdown-choice. You choose what’s standard. You also don’t have to do it because one person (me, in this case) likes it…
But I think for you it’s more for the pleasure of seeiing what you’re capable of… so go ahead :wink:

I am trying to figure out what you meant with this. You can change the opacity of the block text, but if you want to change the opacity of the icons you need to change this setting:

Or is it something else that you meant?

I would like to see the values ​​in a graph that shows the trend. I hoped to achieve this with the ‘smooth line’ option in a graph.

Sorry for my critical tone, but I think this is the clearest way to express it.

Aha… That’s it indeed. Didn’t see it had a seperate color-section as it coincidentally was a good color out of the theme…

Yes, the 0 point problem is still on the list. Just did not had the time to improve this. (I try to focus my attention widget by widget, unless there is a big bug inside it.) I’m not sure yet how I can improve the “smooth” line option. I understand why it is happening, It smooths between the known data points. So you get a smooth line if there are just a few data points. It does not smooth out the datapoints itself like Quickchart seems to do. So if there is a massive change between two data points, it tries to smooth out that jump between the data points resulting in the small jumps in the line.

Ill add it to the bug list

Was already on the list

This is the current list of things I will dive deeper in once I going to clean op the graph widget (not saying I’m going to implement every request :sweat_smile: ):

Maybe this can help improving the existing graph line smooth option (parts of text generated by Gemini AI):
Non smooth version (please only pay attention to the graph line, data from Homey humidity sensor)

Smooth version:

Current DS graph with smooth option:

Non-smooth

(example is in Homey script code, but is just for the concept thinking):

// Each point from the JSON is directly translated to a coordinate
const points = data.map(d => ({
x: getX(new Date(d.tijdstip).getTime()),
y: getY(d.waarde)
}));

Smooth

(with configurable smoothing factor):

const sf = 5; // smoothFactor
var points = ;

// Loop through the data and take the average of the last ‘sf’ points
for (var i = sf; i < rawData.length; i++) {
var sum = 0;
for (var j = 0; j < sf; j++) {
sum += rawData[i - j].v; // Add up values
}
var averageV = sum / sf; // Calculate average

points.push({
x: getX(new Date(rawData[i].t).getTime()),
y: getY(averageV)
});
}

SVG graph non-smooth

(just for the concept): polyline

// A polyline simply connects points with straight lines
var pointsString = “”;
for (var p of points) {
pointsString += p.x + “,” + p.y + " ";
}
svg += ‘’;

SVG graph smooth

Cubic Bézier Path

// We start the path at the first point (M = Move To)
var dPath = "M " + points[0].x + “,” + points[0].y;

for (var i = 0; i < points.length - 1; i++) {
var p0 = points[i];
var p1 = points[i + 1];

// Calculate control points for the curve (0.4 = strong smoothing factor)
var cp1x = p0.x + (p1.x - p0.x) * 0.4;
var cp2x = p1.x - (p1.x - p0.x) * 0.4;

// C stands for Cubic Bézier: cp1, cp2, and the end point[cite: 2]
dPath += " C " + cp1x + “,” + p0.y + " " + cp2x + “,” + p1.y + " " + p1.x + “,” + p1.y;
}

// A path element can draw complex curves[cite: 2]
svg += ‘’;

Comment

  • Calculation: The smooth version includes an extra for-loop to average the values, which removes small noise (jitter) from the graph
  • Mathematics: The smooth version utilizes the C (Cubic Bézier) instruction within a <path> element, whereas the non-smooth version uses the simpler “polyline”
  • Visual: By using control points (cp1x and cp2x), you force the line to leave one point horizontally and enter the next horizontally, creating that characteristically smooth “S-curve”

NEW TEST Version V1.8.6

  • Improved: Widgets that use the icon slide-out now support thin, light, bold, and duotone icon styles.
  • New: Icon accent theme color for duotone icons.
  • New: Markdown “Today & Tomorrow” list from calendar events.
  • New: Time-of-day grouping is optional for calendar markdown.
  • New: Calendar markdown event order is configurable (icon, time, and title).
  • Improved: When icons are on but the default calendar icon is off, column text stays aligned for time and events.
  • Fixed: All markdown table cells align to the top.
  • Improved: Load & Filter iCal flow card now includes Source ID.
  • New: Color blocks can now be configured by event type or calendar source.
  • Improved: Load & Filter iCal handles recurrence exceptions more reliably.
  • Improved: Load & Filter iCal uses much less memory for large calendars.
  • Improved: Markdown links with a caret after the URL open in a new tab; the full markdown editor can set this too.
  • Improved: Text widget Markdown inline icons support every Phosphor weight—Thin, Light, Regular, Bold, Fill, and Duotone - including bracket :ph(…): and :ph-weight ph-name: shorthand, with configurable primary and accent colors for duotone.
  • New: Text widget editor adds Markdown Icon Style (default for :ph-icon-slug: tokens) plus Markdown Icon Accent Color and for the duotone secondary layer.

@Bert_Onraedt I’m not going the quote every request from your post, but I think this version added all the features you wanted. Can you check if the exclusion range of events works in your environment? Also includes a new today tomorrow list. (comparable with your custom script). Note: I will add translations once the text widget is finalised for the stable release. But otherwise I need to change these every time during the development of it.

@Amersfoort This also include an option to choose open the url in the markdown in a new tab (By adding ^ to the syntax)

This new version also supports thin, light, bold, and duotone icon styles. You can even choose the two colors for the duotone version:

Note: only for the text widget and widgets that uses the slide out icon setting. Other widgets will follow later.

Thanks, but no need for the code. The thing is, that I am not sure if I should change it. Like I said, if you send lots of data points it wil try to hit every data point. The smooth option just creates a smooth line while trying to hit every data point. If you want an smooth line why not send less data points to the graph:

I think this is a way better solution, because you can exactly choose the smoothness. Want it smoother? Send less data points.

Yes, thanks, I didn’t know. When I setup a resolution of 24 for last 24 hours graph, do you calculate an average or do you take one measurement per hour (Homey keeps track each 5 minutes for recent data I think).

Small remark (see hour consistency on x-axis):
image
Same graph a few minutes later:
image

It takes a measurements spread of the timespan. I wanted the calculations as lightweight as possible for Homey. (Just in case users are going to update graphs every couple of seconds :sweat_smile: )

This is a 24hr graph I guess, so it advances continuously forward, using the current time as the last value. The time is rounded to the full hour. And it is flipped over on the tipping point. I shall see if I can make this more consistent.

What an update !!

I just ran a few tests & for me, everything is there and working as one can expect. The icons, the colors (also based on source), the layout (now also aligns on top).

A very big thank you, from me.

Small question: If you take something out of the block brackets [ ] it automatically goes to the next line. I can work around this (again own script) by putting for example only the icon or spacer or time in a block in a separate column. I don’t know if there’s other ways to add colors to small parts of the text widget? HTML FONT or CCS STYLE tags don’t seem to work?

Another tiny tiny issue with the line-breaking I noticed in the screenshot below. I don’t think this really needs fixing, just have to make the widget wider if you want this lay-out…

One thing that annoys me in the screenshot is the empty space in front on “Multiday”, " AD Morgen". I implemented an invisible icon to align everything behind the icon neatly below each other (If a user does not want a default icon). But maybe it should only do that if the icon is the first thing in the event line? (I see you have chosen time - icon - event), That’s probably also why “kapper” line breaked although there is seemingly enough room behind the time (but it is not because of the invisible icon).

Also there are a lot of table presets. (Just in case you did not know that, because the standard calendar presets aligned already correctly to the top)

No this is not supported. (Did you read this somewhere in the help file? *Edit: Not a snarky comment, honestly want to know, because I might have some things left over in earlier testing)

Can you explain what exactly you wanted to do, and how you wanted to visualise it?

I was just trying different lay-out options.

My dashboard is pretty grayscale - apart from energy-flows and alert-statusses. I ´d like to give the calendars a source related color - which is possible now - but I also don´t want too much color. So i was trying the block to contain just the icon, or just a ´bullet´… same reason why i was trying html-options for coloring just one character or just the time or…just trying things out.

I know indeed that there´s a lot of table-lay-out, thanks!

For the screenshot the main problem is that the widget is just way to small to fit everything in it. When you enlarge it, it becomes just fine with the ph-spacer you created.