diff --git a/Program.cs b/Program.cs
index a258a89..7184a19 100644
--- a/Program.cs
+++ b/Program.cs
@@ -26,24 +26,29 @@
{
try
{
- var reading = GetLatestReading(Port, Location, led: true);
+ var reading = GetLatestReadingWithRetry(Port, Location, led: true);
+ if (reading is null)
+ {
+ return 2;
+ }
+
+ var json = JsonSerializer.Serialize(reading, SensorReadingsJsonContext.Default.Jciebu2);
if (HasArg(args, "--dry"))
{
- var json = JsonSerializer.Serialize(reading, SensorReadingsJsonContext.Default.Jciebu2);
Console.WriteLine(json);
return 0;
}
- var (statusCode, body) = PostODataAsync(reading).GetAwaiter().GetResult();
+ var (statusCode, _) = PostODataAsync(json).GetAwaiter().GetResult();
if (statusCode >= 200 && statusCode < 300)
{
- Console.WriteLine("ok");
+ Console.WriteLine(json);
return 0;
}
WritePayloadToVarLog(reading);
- Console.Error.WriteLine($"http {statusCode}: {body}");
+ Console.Error.WriteLine($"http {statusCode}");
return 2;
}
catch (Exception ex)
@@ -54,18 +59,47 @@
}
///
+ /// 从传感器读取数据;如果响应太短,随机等待 10 到 30 秒后重试,最多重试 3 次。
+ ///
+ /// 串口设备路径。
+ /// 位置标识,若为空则使用默认值。
+ /// 是否开启读数时的指示灯。
+ /// 解析后的传感器数据。
+ private static Jciebu2? GetLatestReadingWithRetry(string port, string? location, bool led)
+ {
+ const int maxRetries = 3;
+
+ for (var attempt = 0; ; attempt++)
+ {
+ if (TryGetLatestReading(port, location, led, out var reading, out var actualBytes))
+ {
+ return reading;
+ }
+
+ if (attempt >= maxRetries)
+ {
+ Console.Error.WriteLine($"error: response too short: {actualBytes} bytes (need >= 56)");
+ return null;
+ }
+
+ var delaySeconds = Random.Shared.Next(10, 31);
+ Console.Error.WriteLine($"error: response too short: {actualBytes} bytes (need >= 56); retrying in {delaySeconds}s");
+ Thread.Sleep(TimeSpan.FromSeconds(delaySeconds));
+ }
+ }
+
+ ///
/// 将传感器数据发送到配置的 OData 端点。
///
- /// 要发送的传感器数据。
+ /// 要发送的 JSON payload。
/// HTTP 状态码与响应内容。
- private static async Task<(int StatusCode, string Body)> PostODataAsync(Jciebu2 payload)
+ private static async Task<(int StatusCode, string Body)> PostODataAsync(string json)
{
using var client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(TimeoutSeconds)
};
- var json = JsonSerializer.Serialize(payload, SensorReadingsJsonContext.Default.Jciebu2);
using var content = new StringContent(json, Encoding.UTF8, "application/json");
if (!string.IsNullOrEmpty(ODataToken))
@@ -107,9 +141,14 @@
/// 串口设备路径。
/// 位置标识,若为空则使用默认值。
/// 是否开启读数时的指示灯。
- /// 解析后的传感器数据。
- private static Jciebu2 GetLatestReading(string port, string? location, bool led)
+ /// 解析成功时的传感器数据。
+ /// 响应太短时的实际字节数。
+ /// 解析成功则为 true;响应太短则为 false。
+ private static bool TryGetLatestReading(string port, string? location, bool led, out Jciebu2 reading, out int actualBytes)
{
+ reading = null!;
+ actualBytes = 0;
+
using var serial = new SerialPort(port, 115200, Parity.None, 8, StopBits.One)
{
ReadTimeout = 1000,
@@ -135,14 +174,17 @@
WriteWithCrc(serial, latest);
Thread.Sleep(100);
var data = ReadAvailable(serial, TimeSpan.FromSeconds(1));
- var reading = ParseLatestDataLong(data);
+ if (!TryParseLatestDataLong(data, out reading, out actualBytes))
+ {
+ return false;
+ }
var now = DateTimeOffset.UtcNow;
var trimmed = now.AddTicks(-(now.Ticks % TimeSpan.TicksPerSecond));
reading.Ts = trimmed.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'", CultureInfo.InvariantCulture);
reading.Location = string.IsNullOrEmpty(location) ? Location : location;
- return reading;
+ return true;
}
finally
{
@@ -232,16 +274,20 @@
/// 解析“latest data long”响应为传感器数据。
///
/// 设备返回的原始数据。
- /// 解析后的传感器数据。
- private static Jciebu2 ParseLatestDataLong(byte[] data)
+ /// 解析成功时的传感器数据。
+ /// 响应太短时的实际字节数。
+ /// 解析成功则为 true;响应太短则为 false。
+ private static bool TryParseLatestDataLong(byte[] data, out Jciebu2 reading, out int actualBytes)
{
+ reading = null!;
+ actualBytes = data.Length;
+
if (data.Length < 56)
{
- Console.Error.WriteLine($"error: response too short: {data.Length} bytes (need >= 56)");
- Environment.Exit(2);
+ return false;
}
- return new Jciebu2
+ reading = new Jciebu2
{
TemperatureC = S16Le(data, 8) / 100.0,
HumidityRh = U16Le(data, 10) / 100.0,
@@ -269,6 +315,8 @@
PgaFlag = data[54],
SeismicIntensityFlag = data[55]
};
+
+ return true;
}
///