Dashticz - Show your dashboard and how-to's!

Dashticz, alternative dashboard based on HTML, CSS, jQuery

Moderators: leecollings, htilburgs, robgeerts

User avatar
mvveelen
Posts: 678
Joined: Friday 31 October 2014 10:22
Target OS: NAS (Synology & others)
Domoticz version: Beta
Location: Hoorn, The Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by mvveelen »

As an early adaptor and installing Dashticz manually when it was initially released, I tried to find out how to install it now and what version I need when having an RPi3B+ running a Beta version of Domoticz (not in Docker). I would love to make my own dashboard and show it here, but I'm lost and don't want to start with the wrong version. Someone who can give me a nudge in the right direction?
RPi3b+/RFXCOM rfxtrx433E/Shelly/Xiaomi Gateway/Philips HUE Lights/Atag Zone One/2 SunnyBoy inverters/AirconWithMe/P1 smartmeter/Domoticz latest Beta
User avatar
madpatrick
Posts: 636
Joined: Monday 26 December 2016 12:17
Target OS: Linux
Domoticz version: 2024.7
Location: Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by madpatrick »

You can use the master version from github

Code: Select all

git clone https://github.com/Dashticz/dashticz
after this you can try the beta version if you like

Code: Select all

git checkout beta
-= HP server GEN8 Xeon(R) E3-1220L_V2 -=- OZW -=- Toon2 (rooted) -=- Domoticz v2024.7 -=- Dashticz v3.12b on Tab8" =-
User avatar
mvveelen
Posts: 678
Joined: Friday 31 October 2014 10:22
Target OS: NAS (Synology & others)
Domoticz version: Beta
Location: Hoorn, The Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by mvveelen »

Thanks, if I understand correctly it will run in Docker. I'll have to think about that because it's pretty new for me and way different than Dashticz was installed at first. Nevertheless, thanks and I'll keep watching this topic with all kinds of new layouts and ideas.
RPi3b+/RFXCOM rfxtrx433E/Shelly/Xiaomi Gateway/Philips HUE Lights/Atag Zone One/2 SunnyBoy inverters/AirconWithMe/P1 smartmeter/Domoticz latest Beta
User avatar
madpatrick
Posts: 636
Joined: Monday 26 December 2016 12:17
Target OS: Linux
Domoticz version: 2024.7
Location: Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by madpatrick »

mvveelen wrote: Sunday 16 July 2023 19:22 Thanks, if I understand correctly it will run in Docker. I'll have to think about that because it's pretty new for me and way different than Dashticz was installed at first. Nevertheless, thanks and I'll keep watching this topic with all kinds of new layouts and ideas.
No. You need to clone (copy) the files in your webserver directory
-= HP server GEN8 Xeon(R) E3-1220L_V2 -=- OZW -=- Toon2 (rooted) -=- Domoticz v2024.7 -=- Dashticz v3.12b on Tab8" =-
User avatar
mvveelen
Posts: 678
Joined: Friday 31 October 2014 10:22
Target OS: NAS (Synology & others)
Domoticz version: Beta
Location: Hoorn, The Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by mvveelen »

Yikes, I found it and installed it already. Now the tweaking can begin :-) Thanks again!
RPi3b+/RFXCOM rfxtrx433E/Shelly/Xiaomi Gateway/Philips HUE Lights/Atag Zone One/2 SunnyBoy inverters/AirconWithMe/P1 smartmeter/Domoticz latest Beta
User avatar
HansieNL
Posts: 957
Joined: Monday 28 September 2015 15:13
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by HansieNL »

@mvveelen If you are running Domoticz beta it's the best to run Dashticz beta.
If you need help with tweaking you can also check the documentation at https://dashticz.readthedocs.io/en/beta/
Blah blah blah
User avatar
mvveelen
Posts: 678
Joined: Friday 31 October 2014 10:22
Target OS: NAS (Synology & others)
Domoticz version: Beta
Location: Hoorn, The Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by mvveelen »

Ah, I will update this evening then.
RPi3b+/RFXCOM rfxtrx433E/Shelly/Xiaomi Gateway/Philips HUE Lights/Atag Zone One/2 SunnyBoy inverters/AirconWithMe/P1 smartmeter/Domoticz latest Beta
babbel
Posts: 2
Joined: Thursday 26 July 2018 15:02
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by babbel »

Hi all, I'm a long time Domoticz user and recently started with Dashticz. I like it a lot so I'm working on my first dashboard with help of layouts/ideas of many of you here :D
nfuse wrote: Tuesday 11 July 2023 0:34 to keep this topic alive my latest dashboard it need some tuning but i'am really happy with it everything in one page has still my preference.

[ ... ]
Great dashboard nfuse! May I ask you how you got this nice Sonos implementation in that frame? I looked at your provided code but unfortunately could not find any traces of the actual implementation. I am running the sonos-http-api by Jishi on my RPi and the way I now managed to implement some functionality is by creating a Domoticz switch for pretty much all functions (Pause/Play, Vol+/-, add/remove speaker to master), which is constantly being updates via a python script running as cronjob. All these switches are then put on the Dashticz dashboard. See attached image

You implementation is much cleaner in my view and - if you don't mind of course - I would love to learn how you got it implemented that way!
Attachments
sonos_dashticz.png
sonos_dashticz.png (316.78 KiB) Viewed 2711 times
nfuse
Posts: 32
Joined: Thursday 26 March 2020 11:37
Target OS: -
Domoticz version:
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by nfuse »

babbel wrote: Wednesday 19 July 2023 10:23 Hi all, I'm a long time Domoticz user and recently started with Dashticz. I like it a lot so I'm working on my first dashboard with help of layouts/ideas of many of you here :D
nfuse wrote: Tuesday 11 July 2023 0:34 to keep this topic alive my latest dashboard it need some tuning but i'am really happy with it everything in one page has still my preference.

[ ... ]
Great dashboard nfuse! May I ask you how you got this nice Sonos implementation in that frame? I looked at your provided code but unfortunately could not find any traces of the actual implementation. I am running the sonos-http-api by Jishi on my RPi and the way I now managed to implement some functionality is by creating a Domoticz switch for pretty much all functions (Pause/Play, Vol+/-, add/remove speaker to master), which is constantly being updates via a python script running as cronjob. All these switches are then put on the Dashticz dashboard. See attached image

You implementation is much cleaner in my view and - if you don't mind of course - I would love to learn how you got it implemented that way!
well i did a feature request a few years back but i dont think not much people use sonos 8-) so i build my own flask app and request it as a iframe.
i am happy to share the code so you can adapt it to your own needs.

Here are the steps. ow and you need a working sonos api you can find it here https://github.com/chrisns/docker-node-sonos-http-api and here https://github.com/jishi/node-sonos-http-api i allready had that implemented for speech commands doorbel over sonos etc

create the next files following this directory structure: ( i run it in docker but you can start it from the command line to test and tune first)

to run in docker
copy to flask directory
execute from that directory

docker build -t flask-app .
docker run -p 5001:5000 flask-app (5001 port of own choice)

rename in portainer and set to always on unless stopped.

/flaskapp/
/flaskapp/sonos-flask.py
/flaskapp/Dockerfile
/flaskapp/requirements.txt

/flaskapp/static/
/flaskapp/static/css
/flaskapp/static/css/styles.css

/flaskapp/static/img/
/flaskapp/static/img/default_album_art.png
/flaskapp/static/img/next.png
/flaskapp/static/img/pause.png
/flaskapp/static/img/play.png
/flaskapp/static/img/playpause.png
/flaskapp/static/img/previous.png
/flaskapp/static/img/stop.png

/flaskapp/templates/
/flaskapp/templates/index.html
/flaskapp/templates/favicon.ico

sonos-flask.py (start on command line with "python sonos-flask.py")

Code: Select all

from flask import Flask, render_template, request
import requests
import json
import logging

app = Flask(__name__, static_folder='static')
app.logger.setLevel(logging.DEBUG)

rooms = ['keuken', 'woonkamer', 'veranda']  # List of rooms

@app.route('/')
def home():
    states = {}
    for room in rooms:
        response = requests.get(f'http://192.168.2.11:5005/{room}/state') # url from sonos api https://github.com/chrisns/docker-node-sonos-http-api
        if response.status_code == 200:
            state = json.loads(response.text)
            states[room] = state
        else:
            print(f"Couldn't fetch state for room: {room}")
    return render_template('index.html', states=states)  # Assuming you have a template called index.html

@app.route('/<zone>/<action>', methods=['POST'])
def handle_button(zone, action):
    print(f'Button clicked - Zone: {zone}, Action: {action}')
    url = f'http://192.168.2.11:5005/{zone}/{action}' # url from sonos api https://github.com/chrisns/docker-node-sonos-http-api
    response = requests.post(url)
    if response.ok:
        return "Button action performed"
    else:
        return "Error: Button action failed", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
Dockerfile

Code: Select all

# Use the official Python base image with the desired version
FROM python:3.8-slim

# Set the working directory inside the container
WORKDIR /app

# Copy the requirements file and install the dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the rest of the application code
COPY . .

# Expose the port your Flask app is listening on
EXPOSE 5000

# Define the command to run your Flask app when the container starts
CMD ["python", "sonos-flask.py"]
requirements.txt

Code: Select all

flask
requests
styles.css

Code: Select all

@import url('https://fonts.googleapis.com/css2?family=Bad+Script&display=swap');

body {
    background-color: rgba(18, 18, 18, 0.1); /* Set the background color with transparency */
    color: #ffffff;
    font-family: Arial, sans-serif;
    max-width: 700px; /* Set maximum width to 800px */
    margin: 0 auto; /* Center the body horizontally */
}

#currentValue{
	margin-top: 5px;
	font-size: 20px;
    color: #1DB954;
}

.container {
    width: 100%;
    padding-top: 10px;
	margin-bottom: -25;
}



img#album-art {
    width: 220px;
    margin-top: 15px;
    position: absolute;
    border-radius: 20px; /* Set the border-radius to create rounded edges */
    top: 0;
    left: 0;
}

#time-remaining {
	display: flex;
    margin-left: 240px;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-start;
    justify-content: flex-start;
}

.music-button {
    padding: 0;
    width: 50px;
    border-radius: 25%;
    background-color: transparent;
    border: none;
    cursor: pointer;

}

.music-button img {
    width: 100%;
    height: 100%;
}

h1, h2 {
    color: #1DB954;
    display: flex;
	margin-top: 10px;
	margin-bottom: -20px;
    margin-left: 240px;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-start;
    justify-content: flex-start;
}

#current-artist-song {
	font-family: 'Bad Script', cursive;
    font-size: 24px;
	margin-bottom: -25px;
	padding: 0 5px;
	Display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: flex-start;
	animation: scrollText 12s linear infinite;
}

@keyframes scrollText {
  0% {
    transform: translateX(750px);
  }
  100% {
    transform: translateX(240px);
  }
}

.larger-select option { 
	background-color: #333;
}

.larger-select {
    font-size: 18px;
	color: white;
    width: 100px;
    height: 50px;
#	margin-left: 42px;
	background-color: transparent;
	border-radius: 5%;
}

.favorieten option { 
	background-color: #333;
}

.favorieten {
    font-size: 18px;
color: white;
    width: 170px;
    height: 50px;
#	margin-left: 42px;
	background-color: rgba(18, 18, 18, 0.1);
	border-radius: 5%;
}

.controls {
    display: flex;
    margin-left: 240px;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-start;
    justify-content: flex-start;
}

.music-button:hover {
    background-color: #e0e0e0;
}

.volume-slider {
    -webkit-appearance: none;
    width: 80%;
    height: 10px;
    margin-top: 10px;
    border-radius: 5px;
	margin-left: 0px;
    background-color: #f2f2f2;
    outline: none;
    opacity: 0.7;
    -webkit-transition: .2s;
    transition: opacity .2s;
}

.volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background-color: #1DB954;
    cursor: pointer;
}
index.html

Code: Select all

<!DOCTYPE html>
<html>
<head>
    <title>Sonos State</title>
    </style>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">  
</head>
<body>
    <div class="container">
        <div id="current-track-info">
            <h2 id="current-zone">Sonos - Now Playing</h2>
            <p id="current-artist-song">
               <span id="current-artist">-</span> &nbsp;-&nbsp; <span id="current-song"></span>
				<p id="time-remaining"></p>
            </p>			
        </div>
        <img id="album-art" src="" alt="Album Art">
    </div>
    <div class="controls">
		<button id="previous" class="music-button"><img src="/static/img/previous.png" alt="Previous"></button>
		<button id="pause" class="music-button"><img src="/static/img/pause.png" alt="Pause"></button>
        <button id="play" class="music-button"><img src="/static/img/play.png" alt="Play"></button>
        <button id="next" class="music-button"><img src="/static/img/next.png" alt="Next"></button>
        <!-- Buttons and volume slider -->
        <select id="zone-select" class="larger-select">
            <option value="keuken">Keuken</option>
            <option value="woonkamer">Woonkamer</option>
            <option value="veranda">Veranda</option>
        </select>
        <select id="favorite-select" class="favorieten">
			<option value="">select playlist</option>
            <option value="favorite/Happy_Tunes">Happy Tunes</option>
            <option value="favorite/Liever_Hollands">Liever Hollands</option>
			<option value="favorite/Koffiehuis">Koffiehuis</option>
			<option value="favorite/foute_1500">de foute 1500</option>
			<option value="favorite/Q-Music">Q-music</option>
			<option value="favorite/radioNL">Radio NL</option>
			<option value="favorite/100_procent_nl">100% NL</option>
			<option value="favorite/Joy_Radio">Joy Radio</option>
        </select>
        <input type="range" id="volume-slider" class="volume-slider" min="0" max="100" step="1"><p id="currentValue"></p>
    </div>
    
    <script>
        // Function to handle the action for all buttons
        function handleButtonClick(url) {
            // Send a GET request to the specified URL
            fetch(url)
              .then(function(response) {
                // Handle the response if needed
              })
              .catch(function(error) {
                // Handle any errors that occurred during the request
                console.error('Error:', error);
              });
        }
    
        // Get the zone-select element by its id
        var zoneSelect = document.getElementById("zone-select");
    
        // Get all the buttons by their respective ids
        var playButton = document.getElementById("play");
        var pauseButton = document.getElementById("pause");
        var previousButton = document.getElementById("previous");
        var nextButton = document.getElementById("next");
		var musicControls = document.querySelector(".music-controls");
		
			// Hide the pause button initially
			pauseButton.style.display = "none";
    
        // Add click event listeners to the buttons
        playButton.addEventListener("click", function() {
            var selectedValue = zoneSelect.value; // Get the selected value
            var url = "http://192.168.2.11:5005/" + selectedValue + "/play";
            handleButtonClick(url);
						// Toggle visibility of pause and play buttons
			pauseButton.style.display = "inline";
			playButton.style.display = "none";

			// Adjust the positioning of the music controls container
			musicControls.style.left = "50%";
        });
    
        pauseButton.addEventListener("click", function() {
            var selectedValue = zoneSelect.value; // Get the selected value
            var url = "http://192.168.2.11:5005/" + selectedValue + "/pause";
            handleButtonClick(url);
			
			// Toggle visibility of pause and play buttons
			pauseButton.style.display = "none";
			playButton.style.display = "inline";

			// Adjust the positioning of the music controls container
			musicControls.style.left = "50%";
        });
    
        previousButton.addEventListener("click", function() {
            var selectedValue = zoneSelect.value; // Get the selected value
            var url = "http://192.168.2.11:5005/" + selectedValue + "/previous";
            handleButtonClick(url);
        });
    
        nextButton.addEventListener("click", function() {
            var selectedValue = zoneSelect.value; // Get the selected value
            var url = "http://192.168.2.11:5005/" + selectedValue + "/next";
            handleButtonClick(url);
        });
        
        // favorite selector
        var favoriteSelect = document.getElementById("favorite-select");
        
        // Add change event listener to the favorite-select
        favoriteSelect.addEventListener("change", function() {
            var selectedValue = favoriteSelect.value; // Get the selected value
            var zoneValue = zoneSelect.value; // Get the selected zone
            var url = base_url + zoneValue + "/" + selectedValue;
            handleButtonClick(url);
        });
		
        // Function to update the volume slider value
        function updateVolumeSlider(volume) {
            var volumeSlider = document.getElementById("volume-slider");
            volumeSlider.value = volume;
            var currentValue = document.getElementById("currentValue");
            currentValue.textContent = "vol: " + volume;
        }
        
        // Function to handle the volume slider change event
        function handleVolumeChange() {
            var selectedValue = zoneSelect.value; // Get the selected value
            var volumeSlider = document.getElementById("volume-slider");
            var volume = volumeSlider.value;
            var url = "http://192.168.2.11:5005/" + selectedValue + "/volume/" + volume;
            handleButtonClick(url);
        }
    
        // Add change event listener to the volume slider
        var volumeSlider = document.getElementById("volume-slider");
        volumeSlider.addEventListener("change", handleVolumeChange);
    
			var base_url = 'http://192.168.2.11:5005/';
			var selectedZone = localStorage.getItem('selectedZone') || document.getElementById('zone-select').value;
			var oldState = null;

			if (localStorage.getItem('selectedZone')) {
				zoneSelect.value = localStorage.getItem('selectedZone');
				var selectedOption = document.getElementById("zone-select");
				var currentZone = selectedOption.options[selectedOption.selectedIndex].text;
				document.getElementById("current-zone").textContent = "Sonos " + currentZone + " - Now Playing";
			}
    
        async function getState(zone) {
            var url = base_url + zone + '/state';
            let response = await fetch(url);
            if (!response.ok) {
                throw new Error('HTTP error ' + response.status);
            }
            let data = await response.json();
            return data;
        }
    
        function formatTime(seconds) {
            var minutes = Math.floor(seconds / 60);
            var remainingSeconds = seconds % 60;
            return minutes.toString().padStart(2, '0') + ':' + remainingSeconds.toString().padStart(2, '0');
        }
		
		function updateAlbumArt(albumArtUri) {
			var albumArtImg = document.getElementById("album-art");
			if (albumArtUri) {
				albumArtImg.src = albumArtUri;
          } else {
            albumArtImg.src = "/static/img/default_album_art.png";
          }
        }
    
        async function updateState() {
            var newState = await getState(selectedZone);
            if (oldState === null || JSON.stringify(newState) !== JSON.stringify(oldState)) {
                // The state has changed, update the webpage
                document.getElementById('current-song').textContent = newState['currentTrack']['title'];
                document.getElementById('current-artist').textContent = newState['currentTrack']['artist'];

				// Update the album art
				updateAlbumArt(newState['currentTrack']['absoluteAlbumArtUri']);

    
                var elapsedTime = newState['elapsedTime'];
                var trackDuration = newState['currentTrack']['duration'];
                var remainingTime = trackDuration - elapsedTime;
    
                document.getElementById('time-remaining').textContent = formatTime(remainingTime);
    
                oldState = newState;
                
                // Update volume slider value
                updateVolumeSlider(newState['volume']);
                
                // Update the current zone dynamically based on the selected option
                var selectedOption = document.getElementById("zone-select");
                var currentZone = selectedOption.options[selectedOption.selectedIndex].text;
                document.getElementById("current-zone").textContent = "Sonos " + currentZone + " - Now Playing";
            }
        }
    
        // Update the current zone dynamically based on the selected option
        document.getElementById("zone-select").addEventListener("change", function() {
            var selectedOption = document.getElementById("zone-select");
            var currentZone = selectedOption.options[selectedOption.selectedIndex].text;
            document.getElementById("current-zone").textContent = "Sonos " + currentZone + " - Now Playing";
            selectedZone = selectedOption.value; // Update the selected zone
            oldState = null; // Reset old state to force update on zone change
            localStorage.setItem('selectedZone', selectedZone); // Save the selected zone to local storage
            updateState(); // Update the state immediately after zone change
        });
    
        // Initial state update
        updateState();
    
        // Regular state updates every 1 second
        setInterval(updateState, 1000);
    </script>
</body>
</html>
known bugs i have to fix:

- play button needs to presses before it pauses and change the png to pause when changed zones
- green slider point a little to big
- layout improvements

good luck

i updated this post with a zip file of the plugin for your convenience https://processware.datadrop.nl/index.p ... plugin.zip
docker with sonos http api / mosquitto / zigbee2mqtt assistant / portainer / dashticz / nodeJS on windows with Zigbee2Mqtt, and some flask builds of my own
babbel
Posts: 2
Joined: Thursday 26 July 2018 15:02
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by babbel »

Sorry for the late response nfuse! With the rest of the dashboard working very well this sonos thing slipped my mind for a while.
It seems indeed not many people use Sonos in combination with domoticz as there is little to find besides the http-api from jishi.

Impressive work you did with that flask-app! I am not familiar with Flask at all so time to dig into it I guess ;)
Thank you for your detailed steps to get it working. Very much appreciate your time on this and let's see if I can get it to work!
nieass4
Posts: 9
Joined: Sunday 11 December 2016 23:40
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.7
Location: Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by nieass4 »

So I am about to make a nice Dashticz Dashboard.

I see this topic isnt that active anymore.

Anyone got some nice dashboards to share?
With the latest V3 dashticz.
floris74
Posts: 75
Joined: Sunday 30 November 2014 8:41
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Hoorn, Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by floris74 »

Yesss, we are hooked on dashticz. last week i thought, i want the route information for my daughter, when me or my wife is bringing her to the day activity center. But i didnt want the map from maps in the screen, because there is no space :) so finally andt thanks to CHATgpt i got it!! is has basicly 2 functions:
normal of different route
time of travel. (green car normal time, orange busy on the way, red delay , pink extreme delay
its very basic and very handy in our situation. so just sharing. :)
Screenshot_20241217-004328(1).jpg
Screenshot_20241217-004328(1).jpg (323.4 KiB) Viewed 344 times
JanJaap
Posts: 191
Joined: Thursday 12 October 2017 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: Dev
Location: the Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by JanJaap »

@floris this looks really well. Having something like this is relatively high on my wish list (want to have for example a clear display for electricity prices + status of my batteries due to dynamic energy contract). Can you share (a link to) your configuration? So that I've got some sort of a pretty looking starting point....... Also the route prediction to the office would be very cool
RPi 3, Domoticz dev version, Aeon ZWave stick (with a whole bunch of slaves), Zigbee using Zigbee2MQTT, Nest thermo, P1 smart meter on RPi Zero
User avatar
waltervl
Posts: 5148
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by waltervl »

JanJaap wrote: Tuesday 17 December 2024 11:23 @floris this looks really well. Having something like this is relatively high on my wish list (want to have for example a clear display for electricity prices + status of my batteries due to dynamic energy contract).
Did you see the energy dashboard? https://wiki.domoticz.com/Energy_dashboard
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
floris74
Posts: 75
Joined: Sunday 30 November 2014 8:41
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Hoorn, Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by floris74 »

Sure!! i can help you in the right directon for the route. For the energy things follow Walters attention :)

First make a text dummy device (IDX 5098 in my situation)

than python script, i run it with crontab, if the route_data.json file doesnt exist, it will be greated.

Code: Select all

import json
import requests
import subprocess

# Instellingen voor het script
NORMAL_DISTANCE = 77.4  # Normale routeafstand in kilometers
DOMOTICZ_IP = "192.168.1.55"  # Vervang dit door jouw Domoticz IP-adres
DOMOTICZ_IDX = 5098  # IDX van jouw Domoticz device

# Google Maps API: Vul je eigen API-sleutel hieronder in
API_KEY = "YOUR_API_KEY"  # <-- Vervang dit door je eigen API-sleutel!

# Voer de curl-opdracht uit om de routegegevens op te halen
curl_command = (
    "curl -s 'https://maps.googleapis.com/maps/api/directions/json?"
    "origin=Stationsplein+1,+Amsterdam&destination=Stationsplein+1,+Rotterdam"
    f"&key={API_KEY}&language=nl&departure_time=now' -o route_data.json"
)

# Voer de curl-opdracht uit
subprocess.run(curl_command, shell=True)

# Laad de JSON-gegevens uit het bestand
try:
    with open("route_data.json", "r") as f:
        data = json.load(f)
except FileNotFoundError:
    print("Fout: route_data.json niet gevonden. Controleer de API-aanroep.")
    exit()

# Controleer of er een route beschikbaar is
if "routes" in data and len(data["routes"]) > 0:
    # Haal de eerste route op
    route = data["routes"][0]
    leg = route["legs"][0]

    # Haal routegegevens op
    distance_text = leg["distance"]["text"]
    distance = float(distance_text.replace(",", ".").split()[0])
    duration_traffic_text = leg["duration_in_traffic"]["text"]
    duration_traffic = int(duration_traffic_text.split()[0])

    # Controleer of het een afwijkende route is
    if abs(distance - NORMAL_DISTANCE) > 0.05:  # Drempel 50 meter
        route_type = "AFWIJKENDE ROUTE!!"
    else:
        route_type = "Normale route"

    # Verkeersstatus op basis van reistijd
    if duration_traffic < 26:
        traffic_status = "rustig verkeer"
    elif 26 <= duration_traffic < 30:
        traffic_status = "drukte op de weg"
    elif 30 <= duration_traffic < 40:
        traffic_status = "Vertraging!"
    else:
        traffic_status = "Extreme vertraging!!"

    # Bericht opstellen
    message = (
        f"{route_type}, {traffic_status}, {duration_traffic} minuten "
        f"({distance_text})."
    )

    # Update Domoticz met de route-informatie
    url = (
        f"http://{DOMOTICZ_IP}:8080/json.htm?"
        f"type=command&param=udevice&idx={DOMOTICZ_IDX}&svalue={message}"
    )
    try:
        response = requests.get(url)
        if response.status_code == 200:
            print("Succesvol bijgewerkt in Domoticz.")
        else:
            print(f"Fout bij het bijwerken van Domoticz: {response.status_code}")
    except Exception as e:
        print(f"Fout bij het bijwerken van Domoticz: {e}")

    # Herlaad het device in Domoticz
    reload_url = f"http://{DOMOTICZ_IP}:8080/json.htm?type=command&param=refreshdevice&idx={DOMOTICZ_IDX}"
    try:
        response = requests.get(reload_url)
        if response.status_code == 200:
            print("Device succesvol herladen in Domoticz.")
        else:
            print(f"Fout bij het herladen van het device in Domoticz: {response.status_code}")
    except Exception as e:
        print(f"Fout bij het herladen van het device in Domoticz: {e}")

else:
    print("Geen routes gevonden in de JSON-gegevens. Controleer je API-aanroep.")
then my CONFIG.js

Code: Select all

blocks['routeAR'] = {
  type: 'text',             // Geeft tekstuele gegevens weer
  title: 'Van Amsterdam naar Rotterdam :)',   // Titel van het block
  refresh: 60,              // Update elke 60 seconden
  idx: 5098,                // De IDX van Domoticz waar je routegegevens staan
  icon: 'fas fa-car',       // Pictogram (optioneel, afhankelijk van Dashticz-versie)
  width:12,
};
then my custom.css

Code: Select all


/* Kleuren voor de icoontjes afhankelijk van de reistijd */
.warninggreen {
  color: green !important;
}

.warningorangefloor {
  color: #ff6d00 !important;
}

.warningred {
  color: red !important;
}

.warningrozefloor {
  color: #f7088a !important;
}

.warninggrey {
  color: grey !important;
}
them my custom.js

Code: Select all

$(document).ready(function() {
    setInterval(function() {
        var routeData = alldevices['5098']?.Data || '';

        if (!routeData || routeData === "") {
            console.log('Geen data beschikbaar, icoon blijft ongewijzigd.');
            return; // Stop de verdere uitvoering
        }

        console.log('Routegegevens: ' + routeData);

        // Zoek naar de reistijd in minuten
        var match = routeData.match(/(\d+)\s*minuten/);
        var duration_in_traffic = match ? parseInt(match[1]) : null;

        var iconColorClass = 'warninggrey'; // Fallback naar grijs

        if (duration_in_traffic !== null) {
            if (duration_in_traffic < 26) {
                iconColorClass = 'warninggreen'; // Snel
            } else if (duration_in_traffic < 30) {
                iconColorClass = 'warningorangefloor'; // Lichte vertraging
            } else if (duration_in_traffic < 40) {
                iconColorClass = 'warningred'; // Matige vertraging
            } else {
                iconColorClass = 'warningrozefloor'; // Zware vertraging
            }
        }

        // Selecteer het icoon en pas de kleurklasse toe
        var $icon = $('.block_routeAT em:first');
        if ($icon.length === 0) {
            console.error('Icoon niet gevonden in DOM.');
            return;
        }

        // Verwijder oude kleurklassen en voeg de nieuwe kleurklasse toe
        $icon.removeClass('warninggreen warningorangefloor warningred warningrozefloor warninggrey')
             .addClass(iconColorClass);

    }, 3000); // Iets kortere interval (3 seconden)
});
somehow my greyfallback doenst work, and after the refresh of de data of the idx the icon starts white. i dont know how and why, but we used to live with that.
Lokonli
Posts: 2260
Joined: Monday 29 August 2016 22:40
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by Lokonli »

floris74 wrote: Tuesday 17 December 2024 20:00
then my CONFIG.js

Code: Select all

blocks['routeAR'] = {
  type: 'text',             // Geeft tekstuele gegevens weer
  title: 'Van Amsterdam naar Rotterdam :)',   // Titel van het block
  refresh: 60,              // Update elke 60 seconden
  idx: 5098,                // De IDX van Domoticz waar je routegegevens staan
  icon: 'fas fa-car',       // Pictogram (optioneel, afhankelijk van Dashticz-versie)
  width:12,
};
then my custom.css

Code: Select all


/* Kleuren voor de icoontjes afhankelijk van de reistijd */
.warninggreen {
  color: green !important;
}

.warningorangefloor {
  color: #ff6d00 !important;
}

.warningred {
  color: red !important;
}

.warningrozefloor {
  color: #f7088a !important;
}

.warninggrey {
  color: grey !important;
}
them my custom.js

Code: Select all

$(document).ready(function() {
    setInterval(function() {
        var routeData = alldevices['5098']?.Data || '';

        if (!routeData || routeData === "") {
            console.log('Geen data beschikbaar, icoon blijft ongewijzigd.');
            return; // Stop de verdere uitvoering
        }

        console.log('Routegegevens: ' + routeData);

        // Zoek naar de reistijd in minuten
        var match = routeData.match(/(\d+)\s*minuten/);
        var duration_in_traffic = match ? parseInt(match[1]) : null;

        var iconColorClass = 'warninggrey'; // Fallback naar grijs

        if (duration_in_traffic !== null) {
            if (duration_in_traffic < 26) {
                iconColorClass = 'warninggreen'; // Snel
            } else if (duration_in_traffic < 30) {
                iconColorClass = 'warningorangefloor'; // Lichte vertraging
            } else if (duration_in_traffic < 40) {
                iconColorClass = 'warningred'; // Matige vertraging
            } else {
                iconColorClass = 'warningrozefloor'; // Zware vertraging
            }
        }

        // Selecteer het icoon en pas de kleurklasse toe
        var $icon = $('.block_routeAT em:first');
        if ($icon.length === 0) {
            console.error('Icoon niet gevonden in DOM.');
            return;
        }

        // Verwijder oude kleurklassen en voeg de nieuwe kleurklasse toe
        $icon.removeClass('warninggreen warningorangefloor warningred warningrozefloor warninggrey')
             .addClass(iconColorClass);

    }, 3000); // Iets kortere interval (3 seconden)
});
somehow my greyfallback doenst work, and after the refresh of de data of the idx the icon starts white. i dont know how and why, but we used to live with that.
Nice!

I see you use setInterval with refresh of 3000 msec to update the css class.
A bit more elegant solution would be to use the deviceHook function and set the deviceStatus parameter.
See:
https://dashticz.readthedocs.io/en/mast ... evice-hook
JanJaap
Posts: 191
Joined: Thursday 12 October 2017 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: Dev
Location: the Netherlands
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by JanJaap »

waltervl wrote: Tuesday 17 December 2024 13:21
JanJaap wrote: Tuesday 17 December 2024 11:23 @floris this looks really well. Having something like this is relatively high on my wish list (want to have for example a clear display for electricity prices + status of my batteries due to dynamic energy contract).
Did you see the energy dashboard? https://wiki.domoticz.com/Energy_dashboard
Tnx. I like that view indeed. However one of the downsides of Domoticz UI's is that it is one page for each thing where in Dashticz you can combine many things into one page (I have the idea to set up an old tablet for home control running the dashticz ui) so I i'd like to combine Domoticz energy dashboard onto the dashticz page
RPi 3, Domoticz dev version, Aeon ZWave stick (with a whole bunch of slaves), Zigbee using Zigbee2MQTT, Nest thermo, P1 smart meter on RPi Zero
User avatar
waltervl
Posts: 5148
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by waltervl »

JanJaap wrote: Friday 20 December 2024 11:03 Tnx. I like that view indeed. However one of the downsides of Domoticz UI's is that it is one page for each thing where in Dashticz you can combine many things into one page (I have the idea to set up an old tablet for home control running the dashticz ui) so I i'd like to combine Domoticz energy dashboard onto the dashticz page
See viewtopic.php?p=318408#p318408
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
floris1974
Posts: 3
Joined: Sunday 15 December 2024 12:10
Target OS: Linux
Domoticz version:
Contact:

Re: Dashticz - Show your dashboard and how-to's!

Post by floris1974 »

Lokonli wrote: Tuesday 17 December 2024 21:01
Nice!

I see you use setInterval with refresh of 3000 msec to update the css class.
A bit more elegant solution would be to use the deviceHook function and set the deviceStatus parameter.
See:
https://dashticz.readthedocs.io/en/mast ... evice-hook
Thanks. I tried pa's few days, but I can't figure it out with ChatGPT. So inlet it rest for now. Next 2 weeks off, so maybe I have time to fix it!
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest