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'"