updateweatherstation.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. /**
  3. * api/updateweatherstation.php
  4. *
  5. * Weather station data ingestion endpoint.
  6. * Authenticates the station using ID + PASSWORD against client_records,
  7. * then inserts a row into weather_station using PDO prepared statements.
  8. *
  9. * Expected GET params (Weather Underground protocol):
  10. * ID, PASSWORD, dateutc, winddir, windspeedmph, humidity, tempf, ...
  11. */
  12. require_once __DIR__ . '/../config/database.php';
  13. header('Content-Type: text/plain');
  14. // ---------------------------------------------------------------------------
  15. // Authenticate station: ID + PASSWORD must match client_records.wustationid
  16. // and client_records.wuapikey for the calling station.
  17. // ---------------------------------------------------------------------------
  18. $stationId = trim($_GET['ID'] ?? '');
  19. $password = trim($_GET['PASSWORD'] ?? '');
  20. if ($stationId === '' || $password === '') {
  21. http_response_code(401);
  22. echo 'error: missing credentials';
  23. exit;
  24. }
  25. try {
  26. $pdo = getDBConnection();
  27. $stmt = $pdo->prepare(
  28. 'SELECT id FROM client_records WHERE wustationid = ? AND wuapikey = ? LIMIT 1'
  29. );
  30. $stmt->execute([$stationId, $password]);
  31. if (!$stmt->fetch()) {
  32. http_response_code(401);
  33. echo 'error: invalid station credentials';
  34. exit;
  35. }
  36. } catch (PDOException $e) {
  37. error_log('updateweatherstation auth error: ' . $e->getMessage());
  38. http_response_code(500);
  39. echo 'error: server error';
  40. exit;
  41. }
  42. // ---------------------------------------------------------------------------
  43. // Parse and sanitise all numeric / string fields
  44. // ---------------------------------------------------------------------------
  45. /** Cast a GET param to float, returning null if missing or non-numeric. */
  46. function getFloat(string $key): ?float
  47. {
  48. $v = $_GET[$key] ?? null;
  49. if ($v === null || $v === '') return null;
  50. return is_numeric($v) ? (float) $v : null;
  51. }
  52. /** Cast a GET param to int, returning null if missing or non-numeric. */
  53. function getInt(string $key): ?int
  54. {
  55. $v = $_GET[$key] ?? null;
  56. if ($v === null || $v === '') return null;
  57. return is_numeric($v) ? (int) $v : null;
  58. }
  59. $action = trim($_GET['action'] ?? '');
  60. $action = substr($action, 0, 50); // max 50 chars
  61. $dateutc = trim($_GET['dateutc'] ?? '');
  62. if ($dateutc === 'now' || $dateutc === '') {
  63. $dateutc = gmdate('Y-m-d H:i:s');
  64. } else {
  65. // Validate / normalise datetime; reject anything that doesn't parse
  66. $ts = strtotime($dateutc);
  67. $dateutc = $ts !== false ? gmdate('Y-m-d H:i:s', $ts) : gmdate('Y-m-d H:i:s');
  68. }
  69. // Numeric sensor readings
  70. $winddir = getFloat('winddir');
  71. $windspeedmph = getFloat('windspeedmph');
  72. $windgustmph = getFloat('windgustmph');
  73. $windgustdir = getFloat('windgustdir');
  74. $windspdmph_avg2m = getFloat('windspdmph_avg2m');
  75. $winddir_avg2m = getFloat('winddir_avg2m');
  76. $windgustmph_10m = getFloat('windgustmph_10m');
  77. $windgustdir_10m = getFloat('windgustdir_10m');
  78. $humidity = getFloat('humidity');
  79. $dewptf = getFloat('dewptf');
  80. $tempf = getFloat('tempf');
  81. $temp2f = getFloat('temp2f');
  82. $temp3f = getFloat('temp3f');
  83. $temp4f = getFloat('temp4f');
  84. $rainin = getFloat('rainin');
  85. $dailyrainin = getFloat('dailyrainin');
  86. $baromin = getFloat('baromin');
  87. $soiltempf = getFloat('soiltempf');
  88. $soiltemp2f = getFloat('soiltemp2f');
  89. $soiltemp3f = getFloat('soiltemp3f');
  90. $soiltemp4f = getFloat('soiltemp4f');
  91. $soilmoisture = getFloat('soilmoisture');
  92. $soilmoisture2 = getFloat('soilmoisture2');
  93. $soilmoisture3 = getFloat('soilmoisture3');
  94. $soilmoisture4 = getFloat('soilmoisture4');
  95. $leafwetness = getFloat('leafwetness');
  96. $leafwetness2 = getFloat('leafwetness2');
  97. $solarradiation = getFloat('solarradiation');
  98. $UV = getFloat('UV');
  99. $visibility = getFloat('visibility');
  100. $indoortempf = getFloat('indoortempf');
  101. $indoorhumidity = getFloat('indoorhumidity');
  102. // Short string fields
  103. $weather = substr(trim($_GET['weather'] ?? ''), 0, 100);
  104. $clouds = substr(trim($_GET['clouds'] ?? ''), 0, 100);
  105. // ---------------------------------------------------------------------------
  106. // Insert
  107. // ---------------------------------------------------------------------------
  108. try {
  109. $stmt = $pdo->prepare('
  110. INSERT INTO `weather_station`
  111. (action, ID, dateutc,
  112. winddir, windspeedmph, windgustmph, windgustdir,
  113. windspdmph_avg2m, winddir_avg2m, windgustmph_10m, windgustdir_10m,
  114. humidity, dewptf, tempf, temp2f, temp3f, temp4f,
  115. rainin, dailyrainin, baromin, weather, clouds,
  116. soiltempf, soiltemp2f, soiltemp3f, soiltemp4f,
  117. soilmoisture, soilmoisture2, soilmoisture3, soilmoisture4,
  118. leafwetness, leafwetness2, solarradiation, UV, visibility,
  119. indoortempf, indoorhumidity)
  120. VALUES
  121. (:action, :ID, :dateutc,
  122. :winddir, :windspeedmph, :windgustmph, :windgustdir,
  123. :windspdmph_avg2m, :winddir_avg2m, :windgustmph_10m, :windgustdir_10m,
  124. :humidity, :dewptf, :tempf, :temp2f, :temp3f, :temp4f,
  125. :rainin, :dailyrainin, :baromin, :weather, :clouds,
  126. :soiltempf, :soiltemp2f, :soiltemp3f, :soiltemp4f,
  127. :soilmoisture, :soilmoisture2, :soilmoisture3, :soilmoisture4,
  128. :leafwetness, :leafwetness2, :solarradiation, :UV, :visibility,
  129. :indoortempf, :indoorhumidity)
  130. ');
  131. $stmt->execute([
  132. ':action' => $action,
  133. ':ID' => $stationId,
  134. ':dateutc' => $dateutc,
  135. ':winddir' => $winddir,
  136. ':windspeedmph' => $windspeedmph,
  137. ':windgustmph' => $windgustmph,
  138. ':windgustdir' => $windgustdir,
  139. ':windspdmph_avg2m'=> $windspdmph_avg2m,
  140. ':winddir_avg2m' => $winddir_avg2m,
  141. ':windgustmph_10m' => $windgustmph_10m,
  142. ':windgustdir_10m' => $windgustdir_10m,
  143. ':humidity' => $humidity,
  144. ':dewptf' => $dewptf,
  145. ':tempf' => $tempf,
  146. ':temp2f' => $temp2f,
  147. ':temp3f' => $temp3f,
  148. ':temp4f' => $temp4f,
  149. ':rainin' => $rainin,
  150. ':dailyrainin' => $dailyrainin,
  151. ':baromin' => $baromin,
  152. ':weather' => $weather,
  153. ':clouds' => $clouds,
  154. ':soiltempf' => $soiltempf,
  155. ':soiltemp2f' => $soiltemp2f,
  156. ':soiltemp3f' => $soiltemp3f,
  157. ':soiltemp4f' => $soiltemp4f,
  158. ':soilmoisture' => $soilmoisture,
  159. ':soilmoisture2' => $soilmoisture2,
  160. ':soilmoisture3' => $soilmoisture3,
  161. ':soilmoisture4' => $soilmoisture4,
  162. ':leafwetness' => $leafwetness,
  163. ':leafwetness2' => $leafwetness2,
  164. ':solarradiation' => $solarradiation,
  165. ':UV' => $UV,
  166. ':visibility' => $visibility,
  167. ':indoortempf' => $indoortempf,
  168. ':indoorhumidity' => $indoorhumidity,
  169. ]);
  170. echo 'success';
  171. } catch (PDOException $e) {
  172. error_log('updateweatherstation insert error: ' . $e->getMessage());
  173. http_response_code(500);
  174. echo 'error: server error';
  175. }