From e2eeeaefcd7f736d14189adb4591dce44d608f49 Mon Sep 17 00:00:00 2001 From: Holger Sielaff Date: Sat, 28 Jun 2025 16:23:47 +0200 Subject: [PATCH] Added files --- .env | 7 ++ .gitignore | 2 + api.php | 34 ++++++++ bootstrap.php | 51 ++++++++++++ gpx.php | 13 +++ index.php | 6 ++ lib.php | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++ utils | 2 + 8 files changed, 328 insertions(+) create mode 100644 .env create mode 100644 .gitignore create mode 100644 api.php create mode 100644 bootstrap.php create mode 100644 gpx.php create mode 100644 index.php create mode 100644 lib.php create mode 100755 utils diff --git a/.env b/.env new file mode 100644 index 0000000..83ab5b9 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +APIHOST=www.example.com +APIURL=/track/api.php +# The APIKEY from the things network +APIKEY=xxx +DBNAME=track +DBUSER=track +DBPASS=track diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d962d21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +.env.* diff --git a/api.php b/api.php new file mode 100644 index 0000000..1276545 --- /dev/null +++ b/api.php @@ -0,0 +1,34 @@ +write(); + Logging::info('uplink', $headers, $raw); + } else { + db_logging($_GET['type'] ?? 'error', $raw, $headers); + Logging::info($_GET['type'] || 'error', $headers); + } + } catch (Throwable $e) { + error_log($e->getMessage() . ' - see also /tmp/track-error.log'); + Logging::info('error', $e->getMessage(), $headers, $_GET, $_POST, json_decode($raw)); + } +} else { + Logging::info('error', "Not allowed", $headers, $_GET, $_POST, json_decode($raw)); +} + +header("Content-Type: application/json", true, 200); +echo "true"; +exit(0); diff --git a/bootstrap.php b/bootstrap.php new file mode 100644 index 0000000..54054ef --- /dev/null +++ b/bootstrap.php @@ -0,0 +1,51 @@ + PDO::ERRMODE_EXCEPTION, + ] + ); + } + return self::$_pdo; + } +} +$pdo = Config::dbConnection(); diff --git a/gpx.php b/gpx.php new file mode 100644 index 0000000..9f09c21 --- /dev/null +++ b/gpx.php @@ -0,0 +1,13 @@ +exec("CREATE TABLE IF NOT EXISTS logging( + id SERIAL PRIMARY KEY, + request_type VARCHAR, + inserted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + raw JSON, + headers JSON, + _get JSON, + _post JSON + )"); + $stmt = $pdo->prepare("INSERT INTO logging(raw, request_type, headers, _get, _post) VALUES(?, ?, ?, ?, ?)"); + $stmt->execute([$raw_data, $_GET['type'] ?? 'NN', json_encode($headers), json_encode($_GET), json_encode($_POST)]); +} + +class UplinkData +{ + + public $raw; + + public $altitude; + public $longitude; + public $latitude; + public $uplink_token; + public $request_type = 'uplink'; + public $_get; + public $_post; + public $_headers; + public $time; + public $device_id; + + public function __construct(string $raw, array $headers) + { + $this->raw = $raw; + $data = json_decode($raw); + + $this->device_id = $data->end_device_ids->device_id; + $this->time = $data->received_at; + $this->_headers = json_encode($headers); + $this->_post = json_encode($_POST); + $this->_get = json_encode($_GET); + $this->uplink_token = $data->uplink_message->rx_metadata[0]->uplink_token; + $this->latitude = $data->uplink_message->rx_metadata[0]->location->latitude; + $this->longitude = $data->uplink_message->rx_metadata[0]->location->longitude; + $this->altitude = $data->uplink_message->rx_metadata[0]->location->altitude; + #$this->latitude = $data->uplink_message->decoded_payload->latitude; + #$this->altitude = $data->uplink_message->decoded_payload->altitude; + #$this->longitude = $data->uplink_message->decoded_payload->longitude; + } + + public function write() + { + $pdo = Config::dbConnection(); + $stmt = $pdo->prepare("INSERT INTO tracks + ( + raw, device_id, _get, _post, _headers, latitude, + longitude, altitude, time, request_type, uplink_token + ) + VALUES( + ?, ?, ?, ?, ?, ?, + ?, ?, ?, ?, ? + )"); + $args = [ + $this->raw, + $this->device_id, + $this->_get, + $this->_post, + $this->_headers, + $this->latitude, + $this->longitude, + $this->altitude, + $this->time, + $this->request_type, + $this->uplink_token, + ]; + $stmt->execute($args); + } + + public static function get(string $device_id = '', string $from = '', string $to = ''): array + { + $pdo = Config::dbConnection(); + $from = $from ?: $_GET['from'] ?: date('Y-m-d H:i:s', time() - 3600 * 24); + $to = $to ?: date('Y-m-d H:i:s'); + $sql = "SELECT * FROM tracks WHERE request_type = 'uplink' AND time BETWEEN ? AND ?"; + $args = [$from, $to]; + if ($device_id) { + $sql .= " AND device_id = ?"; + $args[] = $device_id; + } + $stmt = $pdo->prepare($sql); + $res = $stmt->execute($args); + $ret = []; + if ($res) { + $ret = []; + foreach ($stmt->fetchAll(PDO::FETCH_OBJ) as $_) { + if(!$_->device_id){ + continue; + } + if ( ! isset($ret[$_->device_id])) { + $ret[$_->device_id] = []; + } + $ret[$_->device_id][] = $_; + } + } + + return $ret; + } + + public static function makePositions(string $device_id = '',string $from = '', string $to='') + { + $data = self::get($device_id, $from, $to); + $tracks = []; + if ($data) { + foreach ($data as $device_id => $resultset) { + if(!isset($tracks[$device_id])){$tracks[$device_id] = [];} + + foreach ($resultset as $res) { + $raw = json_decode($res->raw); + list($lat,$lon) = static::decodePayload($raw, $human); + $tracks[$device_id][] = ['received_at' => $raw->received_at, 'lat' => $lat, 'lon' => $lon,]; + } + } + } + + return [$tracks, $human]; + + } + + public static function makeGPX(string $device_id = '', string $from = '', string $to = ''): string + { + $root = '' + . '' + . 'Track - %s bis %sTrack haltHolguin' + . '%s' + . ''; + $track = 'Trackname %sTrackbeschreibung %s' + . '' + . '%s' + . '' + . ''; + $data = self::get($device_id, $from, $to); + $tracks = []; + if ($data) { + foreach ($data as $device_id => $resultset) { + + $inner = []; + foreach ($resultset as $res) { + $raw = json_decode($res->raw); + list($lat,$lon) = static::decodePayload($raw); + # $inner[] = sprintf('%s', $res->latitude, $res->longitude, $res->altitude, $res->time); + $inner[] = sprintf('%s', $lat, $lon, 0, $raw->received_at); + } + $tracks[] = sprintf($track, $device_id, $device_id, join("\n", $inner)); + } + + return sprintf($root,$from, $to, join("\n", $tracks)); + } + return ''; + } + public static function decodePayload($raw, &$human=[]) + { + $payload=$raw->uplink_message->frm_payload; + $human = file_get_contents('https://1m2m.eu/services/GETPAYLOAD?Human=0&PL='.bin2hex(base64_decode($payload))); + $human = json_decode($human); + if(isset($human->Lat) && isset($human->Lon)){ + return [str_replace(',','.',$human->Lat),str_replace(',','.',$human->Lon)]; + } + return [0,0]; + + } + +} + + +class Logging +{ + public static function info($type, ...$_) + { + global $verbose; + if ($verbose || $type == 'error') { + file_put_contents("/tmp/track-$type.log", json_encode($_) . "\n", FILE_APPEND); + } + } +} + +if ( ! function_exists('getallheaders')) { + function getallheaders(): array + { + $headers = [ + 'Content-type' => 'application/json', + "X-Tts-Domain" => '', + ]; + foreach ($_SERVER as $name => $value) { + if ($name != 'HTTP_MOD_REWRITE' && (substr($name, 0, 5) == 'HTTP_' || $name == 'CONTENT_LENGTH' || $name == 'CONTENT_TYPE')) { + $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', str_replace('HTTP_', '', $name))))); + if ($name == 'Content-Type') { + $name = 'Content-type'; + } + $headers[$name] = $value; + } + } + + return $headers; + } +} diff --git a/utils b/utils new file mode 100755 index 0000000..7622784 --- /dev/null +++ b/utils @@ -0,0 +1,2 @@ +psq="sudo -upostgres psql track -c" +$psq "select count(*) from tracks WHERE request_type = 'uplink'"