mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-11-22 06:23:01 +00:00
Merge branch 'dev'
This commit is contained in:
commit
5f3dc49802
11 changed files with 960 additions and 798 deletions
13
Changelog.md
13
Changelog.md
|
@ -1,4 +1,6 @@
|
||||||
The data displayed has been produced by low-cost devices developed by [Connected Humber](https://www.connectedhumber.org/) members as part of a community driven effort to build a network of smart sensors in the Humber Region.
|
The data displayed has been produced by low-cost devices developed by [Connected Humber](https://www.connectedhumber.org/) members as part of a community driven effort to build a network of smart sensors in the Humber Region.
|
||||||
|
|
||||||
|
**Please read the [Disclaimer](https://github.com/ConnectedHumber/Air-Quality-Web/tree/dev#disclaimer) for important information about the accuracy of our sensors.**
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
This is the changelog for the air quality web interface and its associated HTTP API.
|
This is the changelog for the air quality web interface and its associated HTTP API.
|
||||||
|
@ -7,6 +9,17 @@ This is the changelog for the air quality web interface and its associated HTTP
|
||||||
- `[Code]` refers to internal changes to the code that have no direct impact on the web interface or the HTTP API, but are significant enough to warrant note.
|
- `[Code]` refers to internal changes to the code that have no direct impact on the web interface or the HTTP API, but are significant enough to warrant note.
|
||||||
- `[Docs]` refers to changes to the [documentation](https://aq.connectedhumber.org/__nightdocs/00-Welcome.html).
|
- `[Docs]` refers to changes to the [documentation](https://aq.connectedhumber.org/__nightdocs/00-Welcome.html).
|
||||||
|
|
||||||
|
## v0.13.5
|
||||||
|
- Disable the tour, as it's now causing a crash on startup :-(
|
||||||
|
- [API] Don't return devices in the device lists that have the `visible` flag in the database set to `0`
|
||||||
|
|
||||||
|
## v0.13.4
|
||||||
|
- [API] Fix crash in `list-devices-near` action
|
||||||
|
|
||||||
|
|
||||||
|
## v0.13.3
|
||||||
|
- Update dependencies
|
||||||
|
|
||||||
|
|
||||||
## v0.13.2
|
## v0.13.2
|
||||||
- Improve performance of device graph pop-up
|
- Improve performance of device graph pop-up
|
||||||
|
|
14
README.md
14
README.md
|
@ -13,11 +13,13 @@ The client-side browser application is powered by [Leaflet](https://leafletjs.co
|
||||||
|
|
||||||
Note that this project is _not_ responsible for entering data into the database. This project's purpose is simply to display the data.
|
Note that this project is _not_ responsible for entering data into the database. This project's purpose is simply to display the data.
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
Documentation has moved! You can view it here:
|
Documentation has moved! You can view it here:
|
||||||
|
|
||||||
- https://sensors.connectedhumber.org/__nightdocs/00-Welcome.html
|
- https://sensors.connectedhumber.org/__nightdocs/00-Welcome.html
|
||||||
|
|
||||||
|
|
||||||
## Branches
|
## Branches
|
||||||
- `master`
|
- `master`
|
||||||
- The default branch
|
- The default branch
|
||||||
|
@ -26,6 +28,7 @@ Documentation has moved! You can view it here:
|
||||||
- The development branch
|
- The development branch
|
||||||
- May not always be stable.
|
- May not always be stable.
|
||||||
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
- Readings are taken every 6 minutes as standard.
|
- Readings are taken every 6 minutes as standard.
|
||||||
|
|
||||||
|
@ -37,6 +40,17 @@ The [issue tracker](https://github.com/ConnectedHumber/Air-Quality-Web/issues) i
|
||||||
|
|
||||||
**Please remember: All pull requests should be made against the `dev` branch, not master! The `master` branch is the stable version that automatically gets pushed to production.**
|
**Please remember: All pull requests should be made against the `dev` branch, not master! The `master` branch is the stable version that automatically gets pushed to production.**
|
||||||
|
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
This website displays sensor reading from devices created by individuals with an interest in monitoring their environment and is not endorsed or funded in any way by UK government supported bodies such as DEFRA. It is , however, hoped that this work may be useful in educational applications.
|
||||||
|
|
||||||
|
The sensors, on the map, are installed in different ways, in different enclosures, at different heights and with different exposures to sunlight and wind . This means that, although individual sensors may use the same detectors, those detectors could produce varying results due to the above and also due to component tolerance spread.
|
||||||
|
|
||||||
|
No attempt has been made, by us, to calibrate the sensor readings in any way though the visual representation will include some aggregation of readings.
|
||||||
|
|
||||||
|
If you wish to create a device to display data on this map please register with mattermost.connectedhumber.org and we will provide you with direction and designs to build your own sensor device.
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
- Map: [Leaflet.js](https://leafletjs.com/) showing [OpenStreetMaps](https://www.openstreetmap.org/) using various plugins
|
- Map: [Leaflet.js](https://leafletjs.com/) showing [OpenStreetMaps](https://www.openstreetmap.org/) using various plugins
|
||||||
- Colour manipulation by [chroma.js](https://github.com/gka/chroma.js)
|
- Colour manipulation by [chroma.js](https://github.com/gka/chroma.js)
|
||||||
|
|
2
build
2
build
|
@ -340,7 +340,7 @@ task_deploy() {
|
||||||
subtask_end $?;
|
subtask_end $?;
|
||||||
|
|
||||||
subtask_begin "Unwinding symlinks";
|
subtask_begin "Unwinding symlinks";
|
||||||
find "${temp_dir}" -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;
|
find "${temp_dir}" -type l -not -path "./beta" -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;
|
||||||
subtask_end $?;
|
subtask_end $?;
|
||||||
|
|
||||||
task_end $?;
|
task_end $?;
|
||||||
|
|
46
client_src/js/Helpers/Colourizer.mjs
Normal file
46
client_src/js/Helpers/Colourizer.mjs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function colourize(image, r, g, b) {
|
||||||
|
let canvas = document.createElement("canvas"),
|
||||||
|
context = canvas.getContext("2d");
|
||||||
|
canvas.width = image.width;
|
||||||
|
canvas.height = image.height;
|
||||||
|
|
||||||
|
context.drawImage(image, 0, 0);
|
||||||
|
|
||||||
|
let image_data = context.getImageData(
|
||||||
|
0, 0,
|
||||||
|
canvas.width, canvas.height
|
||||||
|
),
|
||||||
|
buf = new ArrayBuffer(image_data.data.length),
|
||||||
|
view = new Uint32Array(buf),
|
||||||
|
view8 = new Uint8ClampedArray(buf);
|
||||||
|
|
||||||
|
console.log(`Canvas: ${canvas.width}x${canvas.height}, image data: ${image_data.width}x${image_data.height}`);
|
||||||
|
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
for(let y = 0; y < image_data.height; y++) {
|
||||||
|
for(let x = 0; x < image_data.width; x++) {
|
||||||
|
let loc = y*image_data.width + x;
|
||||||
|
//if(image_data.data[loc*4 + 3] == 0) continue
|
||||||
|
|
||||||
|
view[loc] =
|
||||||
|
(image_data.data[loc*4 + 3] << 24) | // Alpha
|
||||||
|
((b+image_data.data[loc*4 + 2])/2 << 16) | // Blue
|
||||||
|
((g+image_data.data[loc*4 + 1])/2 << 8) | // Green
|
||||||
|
(r+image_data.data[loc*4])/2; // Red
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(`Changed ${count} / ${canvas.width*canvas.height} pixels`);
|
||||||
|
|
||||||
|
image_data.data.set(view8);
|
||||||
|
context.putImageData(image_data, 0, 0);
|
||||||
|
|
||||||
|
return canvas.toDataURL();
|
||||||
|
// let image_data = context.getImageData()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default colourize;
|
|
@ -36,6 +36,7 @@ class MapManager {
|
||||||
// Add the attribution
|
// Add the attribution
|
||||||
this.map.attributionControl.addAttribution("Data: <a href='https://connectedhumber.org/'>Connected Humber</a>");
|
this.map.attributionControl.addAttribution("Data: <a href='https://connectedhumber.org/'>Connected Humber</a>");
|
||||||
this.map.attributionControl.addAttribution("<a href='https://github.com/ConnectedHumber/Air-Quality-Web/'>Air Quality Web</a> by <a href='https://starbeamrainbowlabs.com/'>Starbeamrainbowlabs</a>");
|
this.map.attributionControl.addAttribution("<a href='https://github.com/ConnectedHumber/Air-Quality-Web/'>Air Quality Web</a> by <a href='https://starbeamrainbowlabs.com/'>Starbeamrainbowlabs</a>");
|
||||||
|
this.map.attributionControl.addAttribution("<strong><a href='https://github.com/ConnectedHumber/Air-Quality-Web/tree/dev#disclaimer'>Sensor Data Disclaimer</a></strong>");
|
||||||
|
|
||||||
// Setup the UI
|
// Setup the UI
|
||||||
this.ui = new UI(Config, this);
|
this.ui = new UI(Config, this);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import NanoModal from 'nanomodal';
|
||||||
import Config from './Config.mjs';
|
import Config from './Config.mjs';
|
||||||
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
||||||
|
|
||||||
import Tour from './Tour.mjs';
|
// import Tour from './Tour.mjs';
|
||||||
|
|
||||||
function show_nanomodal(html, options = {}) {
|
function show_nanomodal(html, options = {}) {
|
||||||
return new Promise((resolve, _reject) => {
|
return new Promise((resolve, _reject) => {
|
||||||
|
@ -42,7 +42,8 @@ class UI {
|
||||||
this.ui_panel = new SmartSettings("Settings");
|
this.ui_panel = new SmartSettings("Settings");
|
||||||
// this.ui_panel.watch((event) => console.log(event));
|
// this.ui_panel.watch((event) => console.log(event));
|
||||||
|
|
||||||
this.tour = new Tour(this.map_manager);
|
this.tour_enabled = false;
|
||||||
|
if(this.tour_enabled) this.tour = new Tour(this.map_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup() {
|
async setup() {
|
||||||
|
@ -66,6 +67,13 @@ class UI {
|
||||||
document.querySelector("main").classList.remove("working-visual");
|
document.querySelector("main").classList.remove("working-visual");
|
||||||
}).bind(this)
|
}).bind(this)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "button",
|
||||||
|
name: "View disclaimer",
|
||||||
|
callback: ((_event) => {
|
||||||
|
window.open("https://github.com/ConnectedHumber/Air-Quality-Web/tree/dev#disclaimer", "_blank")
|
||||||
|
})
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "button",
|
type: "button",
|
||||||
name: "Report bug",
|
name: "Report bug",
|
||||||
|
@ -83,7 +91,7 @@ class UI {
|
||||||
]);
|
]);
|
||||||
this.ui_panel.setIndex("Reading Type", this.reading_types.findIndex((type) => type.short_descr == "PM25"));
|
this.ui_panel.setIndex("Reading Type", this.reading_types.findIndex((type) => type.short_descr == "PM25"));
|
||||||
|
|
||||||
await this.tour.run_once();
|
if(this.tour_enabled) await this.tour.run_once();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
client_src/marker-old.png
Normal file
BIN
client_src/marker-old.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
|
@ -22,6 +22,7 @@ class MariaDBDeviceRepository implements IDeviceRepository {
|
||||||
public static $column_point = "lat_lon";
|
public static $column_point = "lat_lon";
|
||||||
public static $column_altitude = "device_altitude";
|
public static $column_altitude = "device_altitude";
|
||||||
public static $column_last_seen = "last_seen";
|
public static $column_last_seen = "last_seen";
|
||||||
|
public static $column_visible = "visible";
|
||||||
|
|
||||||
public static $table_name_type = "device_types";
|
public static $table_name_type = "device_types";
|
||||||
public static $column_type_id = "device_type";
|
public static $column_type_id = "device_type";
|
||||||
|
@ -90,7 +91,8 @@ class MariaDBDeviceRepository implements IDeviceRepository {
|
||||||
{$s("table_name")}.{$s("column_last_seen")} AS last_seen
|
{$s("table_name")}.{$s("column_last_seen")} AS last_seen
|
||||||
FROM {$s("table_name")}
|
FROM {$s("table_name")}
|
||||||
JOIN $data_repo_table_meta ON
|
JOIN $data_repo_table_meta ON
|
||||||
$data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")}";
|
$data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")}
|
||||||
|
WHERE {$s("table_name")}.{$s("column_visible")} != 0";
|
||||||
|
|
||||||
if($only_with_location)
|
if($only_with_location)
|
||||||
$sql .= "\nWHERE
|
$sql .= "\nWHERE
|
||||||
|
@ -126,7 +128,8 @@ class MariaDBDeviceRepository implements IDeviceRepository {
|
||||||
{$s("table_name")}.{$s("column_device_type")} = {$s("table_name_type")}.{$s("column_type_id")}
|
{$s("table_name")}.{$s("column_device_type")} = {$s("table_name_type")}.{$s("column_type_id")}
|
||||||
JOIN $data_repo_table_meta ON
|
JOIN $data_repo_table_meta ON
|
||||||
$data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")}
|
$data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")}
|
||||||
WHERE {$s("table_name")}.{$s("column_device_id")} = :device_id;", [
|
WHERE {$s("table_name")}.{$s("column_device_id")} = :device_id
|
||||||
|
AND {$s("table_name")}.{$s("column_visible")} != 0;", [
|
||||||
"device_id" => $device_id
|
"device_id" => $device_id
|
||||||
]
|
]
|
||||||
)->fetch(); // gets the next row from the query
|
)->fetch(); // gets the next row from the query
|
||||||
|
@ -148,11 +151,7 @@ class MariaDBDeviceRepository implements IDeviceRepository {
|
||||||
|
|
||||||
public function get_near_location(float $lat, float $long, int $count) {
|
public function get_near_location(float $lat, float $long, int $count) {
|
||||||
$s = $this->get_static;
|
$s = $this->get_static;
|
||||||
|
$o = $this->get_static_extra;
|
||||||
$data_repo_class = MariaDBMeasurementDataRepository::class;
|
|
||||||
$data_repo_table_meta = $o($data_repo_class, "table_name_metadata");
|
|
||||||
$data_repo_col_datetime = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_datetime")}";
|
|
||||||
$data_repo_col_device_id = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_device_id")}";
|
|
||||||
|
|
||||||
$result = $this->database->query(
|
$result = $this->database->query(
|
||||||
"SELECT
|
"SELECT
|
||||||
|
@ -163,9 +162,8 @@ class MariaDBDeviceRepository implements IDeviceRepository {
|
||||||
ST_DISTANCE_SPHERE(POINT(:latitude, :longitude), {$s("table_name")}.{$s("column_point")}) AS distance_calc,
|
ST_DISTANCE_SPHERE(POINT(:latitude, :longitude), {$s("table_name")}.{$s("column_point")}) AS distance_calc,
|
||||||
{$s("table_name")}.{$s("column_last_seen")} AS last_seen
|
{$s("table_name")}.{$s("column_last_seen")} AS last_seen
|
||||||
FROM {$s("table_name")}
|
FROM {$s("table_name")}
|
||||||
JOIN $data_repo_table_meta ON
|
|
||||||
$data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")}
|
|
||||||
WHERE {$s("table_name")}.{$s("column_point")} IS NOT NULL
|
WHERE {$s("table_name")}.{$s("column_point")} IS NOT NULL
|
||||||
|
AND {$s("table_name")}.{$s("column_visible")} != 0
|
||||||
ORDER BY ST_DISTANCE_SPHERE(POINT(:latitude_again, :longitude_again), {$s("table_name")}.{$s("column_point")})
|
ORDER BY ST_DISTANCE_SPHERE(POINT(:latitude_again, :longitude_again), {$s("table_name")}.{$s("column_point")})
|
||||||
LIMIT :count;", [
|
LIMIT :count;", [
|
||||||
"latitude" => $lat,
|
"latitude" => $lat,
|
||||||
|
|
1626
package-lock.json
generated
1626
package-lock.json
generated
File diff suppressed because it is too large
Load diff
24
package.json
24
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "air-quality-mapper",
|
"name": "air-quality-mapper",
|
||||||
"version": "0.13.0",
|
"version": "0.13.4-dev",
|
||||||
"description": "The web interface and JSON api for the ConnectedHumber Air Quality Monitoring Project.",
|
"description": "The web interface and JSON api for the ConnectedHumber Air Quality Monitoring Project.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
|
@ -18,40 +18,40 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/sbrl/ConnectedHumber-Air-Quality-Interface#readme",
|
"homepage": "https://github.com/sbrl/ConnectedHumber-Air-Quality-Interface#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chart.js": "^2.8.0",
|
"chart.js": "^2.9.3",
|
||||||
"chroma-js": "^2.0.6",
|
"chroma-js": "^2.1.0",
|
||||||
"d3-delaunay": "^5.1.5",
|
"d3-delaunay": "^5.2.1",
|
||||||
"dom-create-element-query-selector": "github:hekigan/dom-create-element-query-selector",
|
"dom-create-element-query-selector": "github:hekigan/dom-create-element-query-selector",
|
||||||
"event-emitter-es6": "^1.1.5",
|
"event-emitter-es6": "^1.1.5",
|
||||||
"iso8601-js-period": "^0.2.1",
|
"iso8601-js-period": "^0.2.1",
|
||||||
"leaflet": "^1.5.1",
|
"leaflet": "^1.6.0",
|
||||||
"leaflet-easyprint": "^2.1.9",
|
"leaflet-easyprint": "^2.1.9",
|
||||||
"leaflet-fullscreen": "^1.0.2",
|
"leaflet-fullscreen": "^1.0.2",
|
||||||
"leaflet.markercluster": "^1.4.1",
|
"leaflet.markercluster": "^1.4.1",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"nanomodal": "^5.1.1",
|
"nanomodal": "^5.1.1",
|
||||||
"shepherd.js": "^5.0.1",
|
"shepherd.js": "^7.1.4",
|
||||||
"smartsettings": "^1.2.3",
|
"smartsettings": "^1.2.3",
|
||||||
"tabs": "^0.2.0",
|
"tabs": "^0.2.0",
|
||||||
"xml-writer": "^1.7.0"
|
"xml-writer": "^1.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chart.js": "^2.8.5",
|
"@types/chart.js": "^2.9.19",
|
||||||
"@types/chroma-js": "^1.4.2",
|
"@types/chroma-js": "^2.0.0",
|
||||||
"@types/d3-delaunay": "^4.1.0",
|
"@types/d3-delaunay": "^4.1.0",
|
||||||
"@types/event-emitter-es6": "^1.1.0",
|
"@types/event-emitter-es6": "^1.1.0",
|
||||||
"@types/leaflet": "^1.5.1",
|
"@types/leaflet": "^1.5.12",
|
||||||
"@types/leaflet-fullscreen": "^1.0.4",
|
"@types/leaflet-fullscreen": "^1.0.4",
|
||||||
"nightdocs": "^1.0.6",
|
"nightdocs": "^1.0.6",
|
||||||
"postcss-copy": "^7.1.0",
|
"postcss-copy": "^7.1.0",
|
||||||
"postcss-import": "^12.0.1",
|
"postcss-import": "^12.0.1",
|
||||||
"rollup": "^1.21.4",
|
"rollup": "^2.7.2",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-json": "^4.0.0",
|
"rollup-plugin-json": "^4.0.0",
|
||||||
"rollup-plugin-node-resolve": "^5.2.0",
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
"rollup-plugin-postcss": "^2.0.3",
|
"rollup-plugin-postcss": "^3.1.1",
|
||||||
"rollup-plugin-replace": "^2.2.0",
|
"rollup-plugin-replace": "^2.2.0",
|
||||||
"rollup-plugin-terser": "^5.1.2"
|
"rollup-plugin-terser": "^5.3.0"
|
||||||
},
|
},
|
||||||
"docpress": {
|
"docpress": {
|
||||||
"github": "ConnectedHumber/Air-Quality-Web",
|
"github": "ConnectedHumber/Air-Quality-Web",
|
||||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
||||||
v0.13.3-dev
|
v0.13.4-dev
|
||||||
|
|
Loading…
Reference in a new issue