muizenval

Observe mouse traps remotely
Log | Files | Refs

trap.js (6789B)


      1 /*
      2 trap { 
      3 	id: int
      4 	name: str?
      5 	status: str
      6 	offline: bool
      7 	locationSearch: bool
      8 	latitude: float?
      9 	longitude: float?
     10 	accuracy: float?
     11 	satellites: int?
     12 	activated: bool
     13 	owner: str
     14 	battery: int
     15 	charging: bool
     16 	temperature: bool
     17 	lastStatus: str
     18 	ownedDate: str
     19 }
     20 */
     21 
     22 var map = L.map('trap-map'),
     23 	socket = io();
     24 
     25 let token = null,
     26 	remote = false,
     27 	traps = {},
     28 	markers = [];
     29 
     30 map.setView([52.283333, 5.666667], 7);
     31 L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
     32 	attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
     33 }).addTo(map);
     34 
     35 socket.on('trap-change', function (trap) {
     36 	var clone,
     37 		append = false;
     38 
     39 	if (traps[trap.id]) {
     40 		Object.assign(traps[trap.id], trap);
     41 
     42 		clone = traps[trap.id].element;
     43 	} else {
     44 		traps[trap.id] = trap;
     45 
     46 		clone = document.getElementById('trap-template').content.cloneNode(true).querySelector('article');
     47 		traps[trap.id].element = clone;
     48 		traps[trap.id].updating = false;
     49 		clone.id = `trap-${trap.id}`;
     50 		append = true;
     51 	}
     52 
     53 	if (!traps[trap.id].updating) {
     54 		var statusIcons = '',
     55 			statusString = '',
     56 			statusIcon,
     57 			batteryIcon,
     58 			tempIcon;
     59 
     60 		if (trap.offline) (statusIcon = 'moon'), (statusString += 'offline');
     61 		else if (trap.activated) (statusIcon = 'circle-exclamation'), (statusString += 'geactiveerd');
     62 		else (statusIcon = 'clock'), (statusString += 'wachtend');
     63 		statusIcons += `<i class='fas fa-${statusIcon}'></i>`;
     64 		//		clone.style.background = '#bdecb6';
     65 		clone.style.background = '#ffffff';
     66 
     67 		if (!trap.offline) {
     68 			if (trap.activated) {
     69 				clone.style.background = '#aec6cf';
     70 			}
     71 			if (trap.charging) (batteryIcon = 'plug-circle-bolt'), (statusString += ', aan het opladen');
     72 			else if (trap.battery == 0) batteryIcon = 'battery-empty';
     73 			else if (trap.battery < 30) batteryIcon = 'battery-quarter';
     74 			else if (trap.battery < 55) batteryIcon = 'battery-half';
     75 			else if (trap.battery < 80) batteryIcon = 'battery-three-quarters';
     76 			else if (trap.battery < 100) batteryIcon = 'battery-full';
     77 			else (batteryIcon = 'plug-circle-xmark'), (statusString += ', problemen met batterij');
     78 			statusIcons += `<i class='fas fa-${batteryIcon}'></i>`;
     79 
     80 			if (trap.temperature > 50) (tempIcon = 'temperature-high'), (statusString += ', oververhit');
     81 			else if (trap.temperature < -10) (tempIcon = 'temperature-low'), (statusString += ', onderkoeld');
     82 			if (tempIcon) statusIcons += `<i class='fas fa-${tempIcon}'></i>`;
     83 
     84 			if (trap.locationSearching) (statusIcons += '<i class="fas fa-satellite"></i>'), (statusString += ', zoekt naar locatie');
     85 		} else {
     86 			clone.style.background = '#eeeeee';
     87 		}
     88 
     89 		clone.querySelector('a.update').onclick = function () {
     90 			var nameSpan = clone.querySelector('span.name'),
     91 				input = nameSpan.querySelector('input');
     92 			if (input) {
     93 				clone.querySelector('a.update').innerHTML = 'bewerken';
     94 				traps[trap.id].updating = false;
     95 				socket.emit('name', { id: trap.id, name: input.value });
     96 			} else {
     97 				nameSpan.innerHTML = `<input type="entry" value="${trap.name}" />`;
     98 				traps[trap.id].updating = true;
     99 				clone.querySelector('a.update').innerHTML = 'klaar';
    100 			}
    101 		};
    102 		clone.querySelector('a.delete').onclick = function () {
    103 			socket.emit('delete', { id: trap.id });
    104 			clone.remove();
    105 			delete traps[trap.id];
    106 		};
    107 		clone.querySelector('a.location').onclick = function () {
    108 			socket.emit('location-search', { id: trap.id, search: !trap.locationSearch });
    109 		};
    110 
    111 		clone.querySelector('span.location-button').innerHTML = trap.locationSearch ? 'locatie vastzetten' : 'locatie zoeken';
    112 		clone.querySelector('span.status-icons').innerHTML = statusIcons;
    113 		clone.querySelector('span.status').innerHTML = statusString;
    114 		clone.querySelector('span.name').innerHTML = trap.name;
    115 		clone.querySelector('span.owner').innerHTML = trap.owner;
    116 		clone.querySelector('span.accuracy').innerHTML = trap.accuracy;
    117 		clone.querySelector('span.satellites').innerHTML = trap.satellites;
    118 		clone.querySelector('span.temperature').innerHTML = trap.temperature;
    119 		clone.querySelector('span.last-status').innerHTML = trap.lastStatus;
    120 		clone.querySelector('span.owned-date').innerHTML = trap.ownedDate;
    121 		if (trap.battery < 100) {
    122 			clone.querySelector('p.battery').style.display = 'inherit';
    123 			clone.querySelector('span.battery').innerHTML = trap.battery;
    124 		} else {
    125 			clone.querySelector('p.battery').style.display = 'none';
    126 		}
    127 		if (trap.locationSearch) {
    128 			clone.querySelector('p.accuracy').style.display = 'inherit';
    129 		} else {
    130 			clone.querySelector('p.accuracy').style.display = 'none';
    131 		}
    132 	}
    133 
    134 	if (append) document.getElementById('trap-container').appendChild(clone);
    135 
    136 	if (trap.accuracy) {
    137 		if (traps[trap.id].marker) {
    138 			traps[trap.id].marker.setLatLng([trap.latitude, trap.longitude]);
    139 		} else {
    140 			traps[trap.id].marker = L.marker([trap.latitude, trap.longitude]).addTo(map).bindPopup(trap.name);
    141 			map.fitBounds(
    142 				Object.values(traps)
    143 					.filter((x) => x.accuracy)
    144 					.map((x) => [x.latitude, x.longitude])
    145 			);
    146 		}
    147 	} else if (traps[trap.id].marker) {
    148 		traps[trap.id].marker.remove();
    149 		traps[trap.id].marker = undefined;
    150 	}
    151 });
    152 
    153 socket.on('trap-remove', function (trap) {
    154 	if (traps[trap.id].marker) traps[trap.id].marker.remove();
    155 	traps[trap.id].element.remove();
    156 
    157 	delete traps[trap.id];
    158 });
    159 
    160 socket.on('statistics', function ({ table, months }) {
    161 	var chart = new CanvasJS.Chart('trap-chart', {
    162 		data: [
    163 			{
    164 				type: 'column',
    165 				dataPoints: [
    166 					{ label: 'Januari', y: months[0] },
    167 					{ label: 'Februari', y: months[1] },
    168 					{ label: 'Maart', y: months[2] },
    169 					{ label: 'April', y: months[3] },
    170 					{ label: 'Mei', y: months[4] },
    171 					{ label: 'Juni', y: months[5] },
    172 					{ label: 'Juli', y: months[6] },
    173 					{ label: 'Augustus', y: months[7] },
    174 					{ label: 'September', y: months[8] },
    175 					{ label: 'October', y: months[9] },
    176 					{ label: 'November', y: months[10] },
    177 					{ label: 'December', y: months[11] },
    178 				],
    179 			},
    180 		],
    181 	});
    182 	chart.render();
    183 	var tbl = document.getElementById('trap-table');
    184 	tbl.innerHTML =
    185 		'<tr><th>Muizenval</th><th>Datum</th><th></th></tr>' +
    186 		table.map(([id, name, date]) => `<tr><td>${name}</td><td>${date}</td><td><a href="javascript:deleteStc(${id})">verwijderen</a></td></tr>`).join('\n');
    187 });
    188 
    189 function deleteStc(id) {
    190 	socket.emit('delete-statistic', id);
    191 }
    192 
    193 function websocket() {
    194 	let ws = new WebSocket('ws://localhost:1612/');
    195 	ws.addEventListener('open', () => ws.send('token'));
    196 	ws.addEventListener('message', (evt) => (token = evt.data));
    197 	ws.addEventListener('close', () => {
    198 		if (token) {
    199 			socket.emit('token', token);
    200 			remote = true;
    201 		} else {
    202 			remote = false;
    203 		}
    204 	});
    205 	ws.addEventListener('error', () => {
    206 		token = null;
    207 		remote = false;
    208 	});
    209 }
    210 
    211 setInterval(websocket, 10000);
    212 
    213 websocket();