basic initial todo list with some docs
This commit is contained in:
parent
74a1303caf
commit
a5792233e2
3 changed files with 390 additions and 0 deletions
132
themes/simple_white/simple_white.org
Normal file
132
themes/simple_white/simple_white.org
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#+SETUPFILE: ~/.emacs.d/org-styles/html/simple_white.theme
|
||||||
|
#+TITLE: Simple White
|
||||||
|
#+AUTHOR: Unknown
|
||||||
|
#+EMAIL: mail@blablub.nil
|
||||||
|
#+OPTIONS: ^:nil p:t
|
||||||
|
|
||||||
|
* Simple White
|
||||||
|
Includes:
|
||||||
|
- [X] CSS
|
||||||
|
- [ ] JAVASCRIPT
|
||||||
|
|
||||||
|
Available as:
|
||||||
|
- [ ] CSS FILE
|
||||||
|
- [ ] JS FILE
|
||||||
|
- [X] SETUPFILE
|
||||||
|
|
||||||
|
* Lists
|
||||||
|
** Todo List
|
||||||
|
*** TODO First todo
|
||||||
|
*** DONE First Done with Date
|
||||||
|
CLOSED: [2021-02-18 Thu 10:12]
|
||||||
|
*** TODO Scheduled
|
||||||
|
SCHEDULED: <2021-02-18 Thu>
|
||||||
|
*** TODO Deadline
|
||||||
|
DEADLINE: <2021-02-18 Thu>
|
||||||
|
*** TODO Date
|
||||||
|
<2021-02-18 Thu>
|
||||||
|
|
||||||
|
** Simple list
|
||||||
|
- List item
|
||||||
|
- List item
|
||||||
|
- List item
|
||||||
|
- List item
|
||||||
|
|
||||||
|
** Sorted List
|
||||||
|
1. List item
|
||||||
|
2. List item
|
||||||
|
3. List item
|
||||||
|
4. List item
|
||||||
|
|
||||||
|
** Checkbox
|
||||||
|
- [ ] List item
|
||||||
|
- [X] List item
|
||||||
|
- [ ] List item
|
||||||
|
- [X] List item
|
||||||
|
|
||||||
|
|
||||||
|
* H1
|
||||||
|
H1 Text
|
||||||
|
** H2
|
||||||
|
H2 Text
|
||||||
|
*** H3
|
||||||
|
H3 Text
|
||||||
|
**** H4
|
||||||
|
H4 Text
|
||||||
|
***** H5
|
||||||
|
H5 Text
|
||||||
|
****** H6
|
||||||
|
H6 Text
|
||||||
|
******* H7
|
||||||
|
H7 Text
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* Table
|
||||||
|
|
||||||
|
| a | b | c | d | e | f |
|
||||||
|
|----+----+----+----+----+----|
|
||||||
|
| 0 | 1 | 2 | 3 | 4 | 5 |
|
||||||
|
| 6 | 7 | 8 | 9 | 10 | 11 |
|
||||||
|
| 12 | 13 | 14 | 15 | 16 | 17 |
|
||||||
|
| 18 | 19 | 20 | 21 | 22 | 23 |
|
||||||
|
| 24 | 25 | 26 | 27 | 28 | 29 |
|
||||||
|
|
||||||
|
|
||||||
|
* Blocks
|
||||||
|
** Center
|
||||||
|
#+begin_center
|
||||||
|
This is a center block
|
||||||
|
#+end_center
|
||||||
|
|
||||||
|
** Comment
|
||||||
|
#+begin_comment
|
||||||
|
This is a comment block
|
||||||
|
#+end_comment
|
||||||
|
|
||||||
|
** Example
|
||||||
|
#+begin_example
|
||||||
|
This is an example block
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
** Quote
|
||||||
|
#+begin_quote
|
||||||
|
This is a quote block
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
** Verse
|
||||||
|
#+begin_verse
|
||||||
|
This is a verse block
|
||||||
|
#+end_verse
|
||||||
|
|
||||||
|
|
||||||
|
** Source Blocks
|
||||||
|
*** Python
|
||||||
|
#+begin_src python :results output :exports both
|
||||||
|
for i in range(10):
|
||||||
|
print(i)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
#+begin_example
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Elisp
|
||||||
|
#+begin_src emacs-lisp :exports both
|
||||||
|
(car '(a b c d))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
: a
|
||||||
|
|
||||||
|
|
3
themes/simple_white/simple_white.theme
Normal file
3
themes/simple_white/simple_white.theme
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#+OPTIONS: org-html-head-include-default-style:nil
|
||||||
|
|
||||||
|
#+HTML_HEAD: <style type="text/css"> * { font-family: "Georgia";}h1, h2, h3, h4, h5, h6,h1 span, h2 span, h3 span, h4 span, h5 span, h6 span,h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-family: "Arial";}pre, code { font-family: Monaco, "Courier New", Courier;}#text-table-of-contents a { font-family: "Arial";}/* @end *//* @group Baseline */body { font-size: 14px; line-height: 1.5em; padding: 0; margin: 0;}h1 { margin: 0; font-size: 1.6666666666666667em; line-height: 0.9em; margin-bottom: 0.9em;}h2 { margin: 0; font-size: 1.5em; line-height: 1em; margin-bottom: 1em;}h3 { margin: 0; font-size: 1.3333333333333333em; line-height: 1.125em; margin-bottom: 1.125em;}h4 { margin: 0; font-size: 1.1666666666666667em; line-height: 1.2857142857142858em; margin-bottom: 1.2857142857142858em;}p, ul, blockquote, pre, td, th, label { margin: 0; font-size: 1em; line-height: 1.5em; margin-bottom: 1.5em;}p.small, #postamble { margin: 0; font-size: 0.8333333333333334em; line-height: 1.8em; margin-bottom: 1.8em;}table { border-collapse: collapse; margin-bottom: 1.5em;}/* @end *//* @group Layout */#content { max-width: 72em; width: 72em; margin-left: auto; margin-right: auto;}/* #header { height: 10em;}*/#table-of-contents { width: 15em; float: left; overflow: auto;}/* #main { */div.outline-2 { width: 52em; float: right; /* The lines below are useful if the "main" div isn't available and div.outline-2 has to be used. */ position: relative;}#postamble { clear: both; text-align: center;}div.outline-2 pre { overflow: auto;}/* @end *//* @group Header */h1.title { margin-top: 10px; text-align: center;}h1.title { font-size: 3em; font-weight: bold; margin-bottom: 0.8em;}/* @end *//* @group Org Keywords */.todo { color: red;}.done { color: green;}.tag { color: blue; text-transform: lowercase; /* This will be obscured by the surrounding span tag, so blank everything. */ background: #fff; border: none; /* position: relative; text-align: right; right: 1em; */}.timestamp {}.timestamp-kwd { /* keyword associated with a time stamp, like SCHEDULED */}.target { /* target for links */}/* @end *//* @group Table of Contents */#table-of-contents h2 { letter-spacing: -0.1em;}#table-of-contents ul,#table-of-contents ol { padding-left: 1em;}/* @end *//* @group Outline Level 2 */.outline-2 h2 { background: #ffc; border-bottom: 1px solid #95c0e6;}.outline-2 h2, .outline-2 h3 { letter-spacing: -0.05em;}.outline-2 { padding: 5px; /* margin-bottom: 10px; */ /* border-top: 1px solid #ccc; */}/* @end */td { border: 1px solid #ccc;}h1 span, h2 span, h3 span, h4 span, h5 span, h6 span { background-color: #eee; padding: 2px; border: 1px solid #ccc;}.outline-1, .outline-2, .outline-3, .outline-4, .outline-5, .outline-6 { margin-left: 2em;}a { text-decoration: none; color: #57d; /* TODO: Find a better colour for this. */}a:hover { border-bottom: 1px dotted #57d;}#postamble p { margin: 0px;}.footpara { display: inline; }.footdef { margin-bottom: 3em; font-size: 80%; }/*]]>*/--></style><script type="text/javascript">/*@licstart The following is the entire license notice for theJavaScript code in this tag.Copyright (C) 2012-2013 Free Software Foundation, Inc.The JavaScript code in this tag is free software: you canredistribute it and/or modify it under the terms of the GNUGeneral Public License (GNU GPL) as published by the Free SoftwareFoundation, either version 3 of the License, or (at your option)any later version. The code is distributed WITHOUT ANY WARRANTY;without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE. See the GNU GPL for more details.As additional permission under GNU GPL version 3 section 7, youmay distribute non-source (e.g., minimized or compacted) forms ofthat code without the copy of the GNU GPL normally required bysection 4, provided you include this license notice and a URLthrough which recipients can access the Corresponding Source.@licend The above is the entire license noticefor the JavaScript code in this tag.*/<!--/*--><![CDATA[/*><!--*/ function CodeHighlightOn(elem, id) { var target = document.getElementById(id); if(null != target) { elem.cacheClassElem = elem.className; elem.cacheClassTarget = target.className; target.className = "code-highlighted"; elem.className = "code-highlighted"; } } function CodeHighlightOff(elem, id) { var target = document.getElementById(id); if(elem.cacheClassElem) elem.className = elem.cacheClassElem; if(elem.cacheClassTarget) target.className = elem.cacheClassTarget; }</script>
|
255
todo.org
Normal file
255
todo.org
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
:PROPERTIES:
|
||||||
|
:LOGGING: PROGRESS(!) DONE(!) CANCELED(!)
|
||||||
|
:END:
|
||||||
|
|
||||||
|
#+SETUPFILE: ~/src/org-themes/src/white_clean/white_clean.theme
|
||||||
|
#+TITLE: E-Bike-Tracker
|
||||||
|
|
||||||
|
* Requirements
|
||||||
|
|
||||||
|
** PROGRESS [#A] Device components
|
||||||
|
- State "PROGRESS" from "TODO" [2022-05-27 Fri 00:42]
|
||||||
|
|
||||||
|
Components needed to develop a PoC:
|
||||||
|
- BMS
|
||||||
|
- GSM (SIM800L is the cheapest and most reliable, i.e. best value for
|
||||||
|
money, but only supports GPRS)
|
||||||
|
- GPS module
|
||||||
|
- BLE module
|
||||||
|
- Accelerometer
|
||||||
|
- Flash for storing local device data (no need for more than 4M?)
|
||||||
|
|
||||||
|
Esp32 has most of these, is pretty cheap and compact and easy to
|
||||||
|
develop on.
|
||||||
|
|
||||||
|
Choose Rust ...
|
||||||
|
|
||||||
|
** PROGRESS [#A] BMS
|
||||||
|
- State "PROGRESS" from "TODO" [2022-05-27 Fri 00:44]
|
||||||
|
Find a BMS that will do good for the battery, measure all cells and
|
||||||
|
give out data needed for various measurments.
|
||||||
|
|
||||||
|
*** TODO [#A] Measure bike battery level
|
||||||
|
|
||||||
|
** TODO [#A] GPS module
|
||||||
|
Find a minimal GPS chip and read from it, test stability and tolerance.
|
||||||
|
|
||||||
|
** PROGRESS [#A] SIM module (GPRS/3G/4G/LTE)
|
||||||
|
- State "PROGRESS" from "TODO" [2022-05-26 Thu 23:57]
|
||||||
|
Find a minimal GSM chip and try to communicate with it.
|
||||||
|
- [[https://www.aliexpress.com/item/4000830117417.html?spm=a2g0o.productlist.0.0.6f9ad49ffLG35d&algo_pvid=594a04bb-8a80-4596-8025-9486269f0923&algo_exp_id=594a04bb-8a80-4596-8025-9486269f0923-28&pdp_ext_f=%7B%22sku_id%22%3A%2210000008680354389%22%7D&pdp_npi=2%40dis%21RSD%21%21288.56%21%21%21%21%21%40210318c916529073178195889e0edd%2110000008680354389%21sea][SIM800L]] - GPRS only, no 3G or 4G ([[https://github.com/lesha108/sim800_ups_monitor/blob/main/src/sim800l.rs][Rust implementation example]]) ... cheapest one there is.
|
||||||
|
|
||||||
|
** TODO [#A] Connect to SIM data (GPRS/3G/4G/LTE)
|
||||||
|
Get a library, or write minimal code that will *only connect to mobile
|
||||||
|
data* and send the coordinates retrieved from the GPS module.
|
||||||
|
|
||||||
|
** TODO [#A] Accelerometer tracking
|
||||||
|
|
||||||
|
** TODO [#B] GSM triangulation for better accuracy
|
||||||
|
|
||||||
|
** CANCELED Hardware button to switch the device on and off?
|
||||||
|
- State "CANCELED" from "WONTFIX" [2022-05-26 Thu 19:55]
|
||||||
|
In case the phone is lost or whatnot, the device needs to have a hw
|
||||||
|
switch so it doesn't bother anyone. There is an edge-case here, maybe
|
||||||
|
even an anti-feature where the bike gets stolen and the thief clicks
|
||||||
|
the hw button and disables all alerts.
|
||||||
|
|
||||||
|
** HOLD [#A] Lock/Unlock mode on the device
|
||||||
|
The device will need to store a state (lock/unlock). When locked and
|
||||||
|
the bike moves, the device will send coordinates through GPRS/3G/4G
|
||||||
|
(depends which GSM module we choose).
|
||||||
|
In this scenario an alert must be sent to the mobile app.
|
||||||
|
|
||||||
|
|
||||||
|
* Software on the device
|
||||||
|
|
||||||
|
We should consider the scenario where we send GPS data independently
|
||||||
|
from other modules (like BMS, Accelerometer ...) because if the bike
|
||||||
|
gets stolen it would be great to send the coordinates as fast as
|
||||||
|
possible. In this case I don't think that battery data would be of
|
||||||
|
much relevance.
|
||||||
|
|
||||||
|
The other way around, when the owner of the device is riding the bike,
|
||||||
|
then there's no need to send GPS, or Accelerometer data to the server.
|
||||||
|
|
||||||
|
Also, the battery status could be measured at different intervals that
|
||||||
|
GPS and acceleration, depending on the mode the device is in ofc.
|
||||||
|
|
||||||
|
Therefore we send every measurment separately for every device.
|
||||||
|
|
||||||
|
#+begin_src plantuml :file img/device_arch.png
|
||||||
|
participant BMS_Thread
|
||||||
|
participant Accelerometer_Thread
|
||||||
|
participant GPS_Thread
|
||||||
|
entity MPSC_Queue
|
||||||
|
|
||||||
|
Consumer -> MPSC_Queue : recv()
|
||||||
|
activate Consumer
|
||||||
|
...
|
||||||
|
BMS_Thread -> MPSC_Queue : send(battery)
|
||||||
|
activate BMS_Thread
|
||||||
|
MPSC_Queue --> Consumer
|
||||||
|
Consumer -> GSM_Modem : write(json)
|
||||||
|
...
|
||||||
|
Accelerometer_Thread -> MPSC_Queue : send(acceleration)
|
||||||
|
activate Accelerometer_Thread
|
||||||
|
MPSC_Queue --> Consumer
|
||||||
|
Consumer -> GSM_Modem : write(json)
|
||||||
|
...
|
||||||
|
GPS_Thread -> MPSC_Queue : send(position)
|
||||||
|
activate GPS_Thread
|
||||||
|
MPSC_Queue --> Consumer
|
||||||
|
Consumer -> GSM_Modem : write(json)
|
||||||
|
...
|
||||||
|
MPSC_Queue --> GPS_Thread
|
||||||
|
MPSC_Queue --> Accelerometer_Thread
|
||||||
|
MPSC_Queue --> BMS_Thread
|
||||||
|
|
||||||
|
deactivate GPS_Thread
|
||||||
|
deactivate Accelerometer_Thread
|
||||||
|
deactivate BMS_Thread
|
||||||
|
deactivate Consumer
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
We'll read different things from different modules, so it's best to
|
||||||
|
have proper structs for all of them.
|
||||||
|
|
||||||
|
#+begin_src rust
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct BatteryStatus {
|
||||||
|
capacity: f32,
|
||||||
|
cells: usize,
|
||||||
|
active_cells: usize,
|
||||||
|
voltage: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct GpsCoordinates {
|
||||||
|
latitude: f32,
|
||||||
|
longitude: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct AccelerometerStatus {
|
||||||
|
acceleration: f32,
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Messages sent from the producers (senders) will be of different
|
||||||
|
types. Therefore we need to create an enum for those messages and fill
|
||||||
|
in a struct that will be serialized to JSON and then sent to the
|
||||||
|
server.
|
||||||
|
|
||||||
|
#+begin_src rust
|
||||||
|
enum SensorData {
|
||||||
|
GPS(GpsCoordinates),
|
||||||
|
Battery(BatteryStatus),
|
||||||
|
Accelerometer(AccelerometerStatus),
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Then in some function executed in a thread ...
|
||||||
|
|
||||||
|
#+begin_src rust
|
||||||
|
fn write_gprs(modem: GsmModem, rx: Receiver) -> Result<()> {
|
||||||
|
let json_for_server = match rx.recv() {
|
||||||
|
GPS(coordinates) => serde_json::to_string(&coordinates)?,
|
||||||
|
Battery(status) => serde_json::to_string(&status)?,
|
||||||
|
Accelerometer(status) => serde_json::to_string(&status)?,
|
||||||
|
};
|
||||||
|
modem.write(json_for_server)?;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Device and phone registration
|
||||||
|
#+begin_src plantuml :file img/registration.png
|
||||||
|
Phone -> Device: Get device ID
|
||||||
|
Device --> Phone: Device ID
|
||||||
|
|
||||||
|
Phone -> Server: Register IDs (device_id, phone_id)
|
||||||
|
Phone <-- Server: Client TLS certificate
|
||||||
|
Phone -> Device: Set TLS certificate
|
||||||
|
Phone <-- Device: TLS certificate set
|
||||||
|
|
||||||
|
Device -> Server: ID verification request
|
||||||
|
Device <-- Server: ID verification response
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO [#A] Phone gets its own device ID
|
||||||
|
The phone needs to get its own device ID as part of the registration
|
||||||
|
procedure. Some code exists in [[https://stackoverflow.com/questions/45031499/how-to-get-unique-device-id-in-flutter][this example]], needs to be verified
|
||||||
|
though.
|
||||||
|
|
||||||
|
** TODO [#A] Phone gets device ID via BLE
|
||||||
|
The phone needs to retrieve the device ID via BLE and pack it together
|
||||||
|
with the phone's ID before sending it to the server as part of the
|
||||||
|
registration procedure.
|
||||||
|
|
||||||
|
** TODO [#A] Generate client certificates with rustls
|
||||||
|
After the CA cert and server keys are all set up, we can use it to
|
||||||
|
generate client certificates for the devices. This should all be done
|
||||||
|
in the web server code, i.e. no exit to shell and call openssl, but
|
||||||
|
use rustls to generate the cert itself.
|
||||||
|
|
||||||
|
** TODO [#A] Phone sets client certs to device
|
||||||
|
The phone needs to retrieve the certificate from the server and pass
|
||||||
|
it to the device.
|
||||||
|
|
||||||
|
** TODO [#A] Device sends an HTTPS request with its own ID
|
||||||
|
The device needs to send a verification HTTPS request using the
|
||||||
|
certificate it received with its ID as the body of the request. This
|
||||||
|
is the final part of the registration procedure.
|
||||||
|
|
||||||
|
** TODO [#A] Handler that registers the phone
|
||||||
|
The phone needs to get its ID and send it within the registration data.
|
||||||
|
|
||||||
|
Registration data:
|
||||||
|
#+begin_src
|
||||||
|
{ phone_id
|
||||||
|
, device_id
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
After the server receives this it needs to generate a client cert that
|
||||||
|
the device will use to send its updates.
|
||||||
|
|
||||||
|
** TODO [#A] Handler that registers the device
|
||||||
|
The final stage of the registration process. The server would need to
|
||||||
|
validate that the request came with the cert generated for that
|
||||||
|
device, and that the device id sent in the body matches the one for
|
||||||
|
which the cert was generated,
|
||||||
|
|
||||||
|
** TODO Investigate if we can use Wireguard on the device
|
||||||
|
See if possible at all. There are some implementations and if it works
|
||||||
|
we will have much better security than tokens, JWTs and the
|
||||||
|
like. maybe not much better than TLS certificates though :)
|
||||||
|
|
||||||
|
If possible, the keys should be generated on the device, but not sure
|
||||||
|
if it has physical limitations (cpu, randomness ...). If the device
|
||||||
|
has physical limitations then we could generate the keys on the phone.
|
||||||
|
|
||||||
|
|
||||||
|
* Tracking
|
||||||
|
The tracking can be done in different ways. Some possible scenarios
|
||||||
|
where we could send alerts:
|
||||||
|
- The device and phone could both send their location, and if they
|
||||||
|
diverge we could start raising alerts on the network.
|
||||||
|
- Add a lock in the app that will trigger alerts when the device moves.
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
** TODO [#A] Report phone coordinates?
|
||||||
|
** TODO [#A] Report device coordinates
|
||||||
|
** TODO [#A] Handle new coordinates on the server
|
||||||
|
- Check if the phone and device are sending same coordinates (or within range).
|
||||||
|
- If the device and phone are paired, do nothing.
|
||||||
|
- If the device and phone are not paired, send alerts to the phone that new coordinates are received.
|
||||||
|
- If the device and phone are not paired and wifi is disconnected, send alerts to the phone and all phones near by (configurable).
|
||||||
|
|
||||||
|
** Outgoing message configuration:
|
||||||
|
- broadcast - broadcast to all subscribers that are listening to broadcast messages
|
||||||
|
- multicast - sends alerts and status reports to a list of devices/users
|
||||||
|
- unicast - sends alerts and status reports only to the phone that owns the device
|
||||||
|
|
||||||
|
** Incoming message configuration:
|
||||||
|
- broadcast - receives and shows all alerts that are broadcasting outgoing messages
|
||||||
|
- multicast - receives and shows alerts from a list of device/users
|
Loading…
Reference in a new issue