Skip to content

Instantly share code, notes, and snippets.

@sam2332
Last active September 4, 2024 17:18
Show Gist options
  • Save sam2332/3c7c9730a39a1990d193bd3540a353c4 to your computer and use it in GitHub Desktop.
Save sam2332/3c7c9730a39a1990d193bd3540a353c4 to your computer and use it in GitHub Desktop.
Home Assistant Trip Card
type: custom:trips-card
title: Lily Trips
person: person.lily
homeZone: home
hours: 24
import "https://unpkg.com/wired-card@0.8.1/wired-card.js?module";
import "https://unpkg.com/wired-toggle@0.8.0/wired-toggle.js?module";
import { LitElement, html, css } from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module";
class TripsCard extends LitElement {
static get properties() {
return {
person: { type: String },
homeZone: { type: String },
hours: { type: Number },
trips: { type: Array }
};
}
constructor() {
super();
this.trips = [];
}
setConfig(config) {
if (!config.person) {
throw new Error("The 'person' configuration is required");
}
if (!config.homeZone) {
throw new Error("The 'homeZone' configuration is required");
}
this.person = config.person;
this.homeZone = config.homeZone;
this.hours = config.hours || 24; // Default to 24 hours if not specified
this.title = config.title || 'Trips';
}
async connectedCallback() {
super.connectedCallback();
await this.fetchHistory();
}
async fetchHistory() {
const endDate = new Date();
const startDate = new Date(endDate.getTime() - this.hours * 3600000);
const response = await this.hass.callApi('GET', `history/period/${startDate.toISOString()}?filter_entity_id=${this.person}`);
this.processTrips(response);
}
processTrips(data) {
let lastStateWasHome = false;
let currentTrip = null;
this.trips = [];
data[0].forEach(entry => {
const currentStateIsHome = entry.state === this.homeZone;
if (!currentStateIsHome && lastStateWasHome) {
currentTrip = { start: entry.last_changed, stops: [] };
} else if (currentStateIsHome && currentTrip) {
currentTrip.end = entry.last_changed;
this.trips.push(currentTrip);
currentTrip = null;
}
lastStateWasHome = currentStateIsHome;
});
if (currentTrip) {
currentTrip.end = "Ongoing";
this.trips.push(currentTrip);
}
this.requestUpdate();
}
formatDate(dateString) {
const date = new Date(dateString);
let hours = date.getHours();
let minutes = date.getMinutes();
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes;
return `${hours}:${minutes} ${ampm}`;
}
groupTripsByDate() {
const tripsByDate = new Map();
this.trips.forEach(trip => {
const startDate = new Date(trip.start).toLocaleDateString();
if (!tripsByDate.has(startDate)) {
tripsByDate.set(startDate, []);
}
tripsByDate.get(startDate).push(trip);
});
return tripsByDate;
}
formatTime(dateString) {
const date = new Date(dateString);
let hours = date.getHours();
let minutes = date.getMinutes();
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes;
return `${hours}:${minutes} ${ampm}`;
}
render() {
const groupedTrips = this.groupTripsByDate(); // Get trips grouped by date
// Convert the Map to an array and sort by date in descending order
const sortedDates = Array.from(groupedTrips).sort((a, b) => new Date(b[0]) - new Date(a[0]));
return html`
<ha-card>
<div class="card-header">
<div class="name" style="cursor: pointer;">${this.title}</div>
</div>
<div class="card-content">
${sortedDates.map(([date, trips]) => html`
<div>${date}</div>
<ul>
${trips.map(trip => html`
<li @click="${() => this.selectTrip(trip)}">
${this.formatTime(trip.start)} - ${trip.end ? this.formatTime(trip.end) : 'Ongoing'}
</li>
`)}
</ul>
`)}
</div>
</ha-card>
`;
}
selectTrip(trip) {
if (!trip.start) return; // Guard clause if no start time is available
const baseUrl = `${window.location.origin}/logbook`;
const startTime = new Date(trip.start).toISOString();
const endTime = trip.end ? new Date(trip.end).toISOString() : new Date().toISOString();
// Here, end_date is set exactly to end_time, not a day later
const logbookUrl = `${baseUrl}?entity_id=${encodeURIComponent(this.person)}&start_time=${encodeURIComponent(startTime)}&end_time=${encodeURIComponent(endTime)}&start_date=${encodeURIComponent(startTime)}&end_date=${encodeURIComponent(endTime)}`;
// Open in a new tab
window.open(logbookUrl, '_blank');
}
calculateDuration(trip) {
if (!trip.end || trip.end === "Ongoing") {
return "Ongoing";
}
const startDate = new Date(trip.start);
const endDate = new Date(trip.end);
return `${Math.round((endDate - startDate) / 60000)} minutes`; // Duration in minutes
}
}
customElements.define('trips-card', TripsCard);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment