коррекция индикации микрофона

This commit is contained in:
Maxim
2026-07-06 15:18:26 +03:00
parent 8dcaee3d61
commit 243541fcd6
4 changed files with 54 additions and 6 deletions

View File

@@ -142,9 +142,17 @@ D7 = GPIO22
```bash ```bash
sudo apt update sudo apt update
sudo apt install -y golang git build-essential wiringpi nodejs npm sudo apt install -y golang git build-essential wiringpi nodejs npm alsa-utils
``` ```
> `alsa-utils` нужен для монитора уровня звука (использует `arecord`). Проверить, что микрофон виден системе:
> ```bash
> arecord -l
> # **** List of CAPTURE Hardware Devices ****
> # card 3: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
> ```
> Если список пуст — микрофон не подключён или не определился, монитор звука будет отдавать `sound_level: 0`.
### 2. Клонирование и сборка ### 2. Клонирование и сборка
```bash ```bash
@@ -282,7 +290,7 @@ sudo nft add rule inet filter input iifname "wlan0" tcp dport 8080 accept
```bash ```bash
GET /api/health GET /api/health
# Статус сервера, uptime, статистика # Статус сервера, uptime, статистика, sound_level (0-100, уровень с микрофона)
GET /api/latest GET /api/latest
# Последние данные и история (10 записей) # Последние данные и история (10 записей)
@@ -350,6 +358,25 @@ GET /api/log/events?limit=100
ls -la /tmp/gpio_pipe ls -la /tmp/gpio_pipe
``` ```
### Если индикатор "🔊 ЗВУК" на dashboard не реагирует на микрофон:
1. **Проверьте, что arecord установлен и видит микрофон:**
```bash
which arecord
arecord -l
```
2. **Проверьте лог сервера при запуске** — если микрофон не найден, будет строка:
```
Аудио-монитор не запущен (микрофон недоступен?): ...
```
3. **Проверьте права доступа к аудио-устройству** (сервис должен работать от пользователя из группы `audio`):
```bash
groups <user>
sudo usermod -aG audio <user>
```
--- ---
## Wi-Fi режим Raspberry Pi ## Wi-Fi режим Raspberry Pi

View File

@@ -19,6 +19,7 @@ import (
"time" "time"
"gpio-monitor/internal/adapter" "gpio-monitor/internal/adapter"
"gpio-monitor/internal/audio"
"gpio-monitor/internal/logger" "gpio-monitor/internal/logger"
"gpio-monitor/internal/pipe" "gpio-monitor/internal/pipe"
) )
@@ -28,8 +29,9 @@ import (
var webFiles embed.FS var webFiles embed.FS
type API struct { type API struct {
buf *adapter.RingBuffer buf *adapter.RingBuffer
startTime time.Time startTime time.Time
audioMonitor *audio.Monitor
} }
func writeJSON(w http.ResponseWriter, v any) { func writeJSON(w http.ResponseWriter, v any) {
@@ -409,6 +411,11 @@ func (a *API) HandleHealth(w http.ResponseWriter, r *http.Request) {
now := time.Now() now := time.Now()
soundLevel := 0
if a.audioMonitor != nil {
soundLevel = a.audioMonitor.GetLevel()
}
writeJSON(w, map[string]any{ writeJSON(w, map[string]any{
"status": status, "status": status,
"uptime_sec": time.Since(a.startTime).Seconds(), "uptime_sec": time.Since(a.startTime).Seconds(),
@@ -418,6 +425,7 @@ func (a *API) HandleHealth(w http.ResponseWriter, r *http.Request) {
"latest": latest, "latest": latest,
"stats": a.buf.Stats(), "stats": a.buf.Stats(),
"server_time": now.Format("02.01.2006 15:04"), "server_time": now.Format("02.01.2006 15:04"),
"sound_level": soundLevel,
}) })
} }
@@ -638,6 +646,13 @@ func main() {
// 4. RingBuffer с настройкой размера // 4. RingBuffer с настройкой размера
buf := adapter.NewRingBuffer(*bufferSize) buf := adapter.NewRingBuffer(*bufferSize)
// 4.5 Монитор уровня звука с микрофона
audioMonitor := audio.NewMonitor()
if err := audioMonitor.Start(); err != nil {
log.Printf("Аудио-монитор не запущен (микрофон недоступен?): %v", err)
}
defer audioMonitor.Stop()
// 5. PipeReader с настройками // 5. PipeReader с настройками
pipeReader := pipe.NewPipeReader(buf, dataLogger, humanLogger, monitor, eventLogger, config) pipeReader := pipe.NewPipeReader(buf, dataLogger, humanLogger, monitor, eventLogger, config)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@@ -646,8 +661,9 @@ func main() {
// ===== API И WEB СЕРВЕР ===== // ===== API И WEB СЕРВЕР =====
api := &API{ api := &API{
buf: buf, buf: buf,
startTime: time.Now(), startTime: time.Now(),
audioMonitor: audioMonitor,
} }
// ===== API ===== // ===== API =====

View File

@@ -20,6 +20,7 @@ import {
setBars, setBars,
setSignal, setSignal,
setAudioIndicator, setAudioIndicator,
setSoundLevel,
DOM, DOM,
setChannelValue, setChannelValue,
setChannelCurrentValue, setChannelCurrentValue,
@@ -254,6 +255,8 @@ async function update(): Promise<void> {
setServerTime(health.server_time); setServerTime(health.server_time);
} }
setSoundLevel(health.sound_level ?? 0);
const isOnline = health.pipe_alive && health.has_data; const isOnline = health.pipe_alive && health.has_data;
if (isOnline) { if (isOnline) {
@@ -384,6 +387,7 @@ async function update(): Promise<void> {
setServerTime("--:--:--"); setServerTime("--:--:--");
setBars(0, true); setBars(0, true);
setSignal(0, true); setSignal(0, true);
setSoundLevel(0);
resetBufferTracking(); resetBufferTracking();
if (lastSignalLevel > 0) { if (lastSignalLevel > 0) {

View File

@@ -8,6 +8,7 @@ interface HealthResponse {
has_data: boolean; has_data: boolean;
latest: number; latest: number;
server_time?: string; server_time?: string;
sound_level?: number;
stats: { stats: {
filled: number; filled: number;
bytes_per_sec: number; bytes_per_sec: number;