# MeshCore — Relay + DS18B20 на базе Companion Radio

## 1. Что это

Модификация прошивки `companion_radio` из MeshCore. Устройство получает по LoRa-мешу приватные команды и управляет реле, а также отвечает на запросы температуры с DS18B20.

## 2. Откуда брать проект

```bash
git clone --depth 1 https://github.com/meshcore-dev/MeshCore.git
cd MeshCore
```

## 3. Что нужно установить

### PlatformIO
- Установить Python 3
- Установить PlatformIO: `pip install platformio`
- Или установить VS Code + расширение PlatformIO

### Зависимости (добавить в platformio.ini)
В секцию `[arduino_base]`, в `lib_deps` добавить:
```
paulstoffregen/OneWire @ ^2.3.7
milesburton/DallasTemperature @ ^3.11.0
```

## 4. Какие файлы править

Базовый проект — `examples/companion_radio/`.

### Файлы для изменения:

| Файл | Что делать |
|------|------------|
| `platformio.ini` | Добавить OneWire и DallasTemperature в lib_deps; для nRF52 добавить env (раздел 7.3) |
| `examples/companion_radio/MyMesh.h` | Добавить #include, пины, поле OneWire/DallasTemperature, метод `readTemperature()` |
| `examples/companion_radio/MyMesh.cpp` | В конструктор — инициализация OneWire, в begin() — `_tempSensor.begin()`, реализовать `readTemperature()`, изменить `onMessageRecv()` |
| `examples/companion_radio/main.cpp` | В `setup()` добавить `pinMode(RELAY_PIN, OUTPUT)` |

### Подключение железа (ESP32):

| Пин | Назначение |
|-----|------------|
| GPIO 4 | Реле (RELAY_PIN) |
| GPIO 5 | DS18B20 Data (ONE_WIRE_BUS) |
| 3.3V | DS18B20 VCC (через 4.7k подтяжку к Data) |
| GND | Общий |

### Параметры радио (ESP32)

В `platformio.ini` в вашей env-секции (например `[env:esp32dev_companion_radio_usb]`) переопределить:

```ini
build_flags = ${arduino_base.build_flags}
  -D LORA_FREQ=868.731018
  -D LORA_BW=62.5
  -D LORA_SF=7
  -D LORA_CR=7
```

Для хэша пути 1 байт в `MyMesh.cpp` в конструкторе указать:

```cpp
_prefs.path_hash_mode = 0;
```

Для **nRF52840 (XIAO)** пины по умолчанию: `RELAY_PIN = D6 (P0.08)`, `ONE_WIRE_BUS = D7 (P0.09)` — смотрите раздел 7.2.

### Автоматическая отправка advertise каждые 30 минут

В `MyMesh.h` добавить поле:

```cpp
  float readTemperature();

private:
  unsigned long _next_advert_ms;
  OneWire _oneWire;
  DallasTemperature _tempSensor;
```

В `MyMesh.cpp` в конструкторе инициализировать:

```cpp
MyMesh::MyMesh(...) : BaseChatMesh(...), _oneWire(ONE_WIRE_BUS), _tempSensor(&_oneWire) {
  _next_advert_ms = 0;
  // ... остальной код ...
}
```

В `MyMesh::loop()` (или в `main.cpp` в `loop()`) добавить проверку таймера:

```cpp
void MyMesh::loop() {
  BaseChatMesh::loop();  // существующий вызов

  // advertise каждые 30 минут (1800000 мс)
  if (millisHasNowPassed(_next_advert_ms)) {
    advert();
    _next_advert_ms = futureMillis(1800000);
  }
}
```

Либо ещё проще — в `main.cpp`:

```cpp
void loop() {
  static unsigned long next_advert = 0;
  the_mesh.loop();
  sensors.loop();
  // ... остальной код ...

  if (millisHasNowPassed(next_advert)) {
    the_mesh.advert();
    next_advert = futureMillis(1800000);
  }
}
```

## 5. Команды (приватные сообщения узлу)

| Команда | Ответ | Действие |
|---------|-------|----------|
| `on1234` | `relay on` | Реле включено |
| `off1234` | `relay off` | Реле выключено |
| `temp` | `temp: 23.5 C` | Температура с DS18B20 |
| `state` | `temp: 23.5 C, relay: ON` | Температура + состояние реле |

Цифра `1234` — код доступа к реле (можно сменить в `RELAY_CODE`).

## 6. Как залить

```bash
cd MeshCore
# для конкретной платы, например ESP32:
pio run -e <board_name> -t upload
# или открыть в VS Code + PlatformIO и собрать через IDE
```

## 7. Версия для nRF52840 + HT-RA62 (SX1262)

### 7.1 Что за связка

**nRF52840** — популярный MCU с BLE. **HT-RA62** — LoRa-модуль на чипе SX1262 (аналог E22-900Mxx).

Можно использовать любую плату на nRF52840 + внешний HT-RA62 по SPI. Самый популярный вариант — **Seeed XIAO nRF52840** + HT-RA62 на макетной плате.

### 7.2 Распиновка XIAO nRF52840 + HT-RA62

| Пин XIAO | GPIO nRF52 | HT-RA62 | Назначение |
|----------|------------|---------|------------|
| D0  | P0.02 | NSS  | CS (SPI chip select) |
| D1  | P0.03 | DIO1 | IRQ (прерывание) |
| D2  | P0.04 | BUSY | Занятость модуля |
| D3  | P0.05 | RESET | Сброс |
| D4  | P0.06 | RXEN | Включение RX (если есть) |
| D5  | P0.07 | TXEN | Включение TX (если есть) |
| D6  | P0.08 | (свободен) | **Реле (RELAY_PIN)** |
| D7  | P0.09 | (свободен) | **DS18B20 Data (ONE_WIRE_BUS)** |
| D8  | P0.10 | SCK  | SPI clock |
| D9  | P0.28 | MO   | SPI MOSI |
| D10 | P0.02 | MI   | SPI MISO |
| 3.3V | —   | VCC  | 3.3V питание |
| GND | —    | GND  | Общий |

> **Важно:** У HT-RA62 DIO2 настроен как RF-переключатель, DIO3 — 1.8V для TCXO (задаётся в коде).

**Свободные пины XIAO nRF52840 после подключения:**

| Пин | Назначение | Можно |
|-----|------------|-------|
| D0  (P0.01) | GPIO | цифровой вход/выход |
| D5  (P0.06) | RXEN (HT-RA62) | **да** — если RXEN не используется (у HT-RA62 коммутация RF уже через DIO2) |
| A0  (P0.31) | ADC/GPIO | аналоговый или цифровой |
| A1  (P0.29) | ADC/GPIO | аналоговый или цифровой |
| A2  (P0.30) | ADC/GPIO | аналоговый или цифровой |

**Занято:** D1(IRQ), D2(BUSY), D3(RESET), D4(NSS), D6(реле), D7(DS18B20), D8(SCK), D9(MOSI), D10(MISO) — 9 пинов.  
**Свободно:** 4–5 пинов (D0, D5, A0, A1, A2) для кнопок, светодиодов или доп. датчиков.

### 7.3 Что добавить в platformio.ini

В конец файла `platformio.ini` дописать:

```ini
; ===== nRF52840 + HT-RA62 (SX1262) =====
[Xiao_nrf52]
extends = nrf52_base
board = seeed-xiao-afruitnrf52-nrf52840
board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52_base.build_flags}
  -D USE_SX1262
  -D LORA_TX_POWER=22
  -D ADVERT_NAME="Relay"
  -D LORA_FREQ=868.731018
  -D LORA_BW=62.5
  -D LORA_SF=7
  -D LORA_CR=7

[env:Xiao_nrf52_companion_radio_usb]
extends = Xiao_nrf52
build_src_filter = ${nrf52_base.build_src_filter}
  +<examples/companion_radio/>

[env:Xiao_nrf52_companion_radio_ble]
extends = Xiao_nrf52
build_flags = ${Xiao_nrf52.build_flags}
  -D BLE_PIN_CODE=123456
build_src_filter = ${nrf52_base.build_src_filter}
  +<examples/companion_radio/>
```

Значения по умолчанию в `[arduino_base]` переопределяются в `Xiao_nrf52`.

### 7.3.1 Хэш пути 1 байт

В `MyMesh.h` перед классом `MyMesh` добавить:

```cpp
#define ADVERT_NAME   "Relay"
// хэш пути — 1 байт (mode 0)
```

В конструкторе `MyMesh` (в `MyMesh.cpp`) явно установить `path_hash_mode`:

```cpp
_prefs.path_hash_mode = 0;  // 0 = 1 байт, 1 = 2 байта, 2 = 3 байта
```

Либо в `main.cpp` можно задать через define и использовать в `platformio.ini`:

```ini
  -D PATH_HASH_MODE=0
```

а в `MyMesh.cpp`:

```cpp
#ifndef PATH_HASH_MODE
  #define PATH_HASH_MODE 0
#endif
...
_prefs.path_hash_mode = PATH_HASH_MODE;
```

### 7.3.2 Итоговые параметры радио

| Параметр | Значение |
|----------|----------|
| Частота | 868.731018 МГц |
| Полоса (BW) | 62.5 кГц |
| Spreading Factor | 7 |
| Coding Rate | 7 |
| Хэш пути | 1 байт |

### 7.4 Как собрать и прошить

```bash
export FIRMWARE_VERSION=v1.0.0

# Собрать прошивку (USB Serial)
pio run -e Xiao_nrf52_companion_radio_usb

# Собрать прошивку (BLE)
pio run -e Xiao_nrf52_companion_radio_ble

# После сборки .uf2 файл будет здесь:
# .pio/build/Xiao_nrf52_companion_radio_usb/firmware.uf2
```

**Способы прошивки nRF52840:**

| Метод | Описание |
|-------|----------|
| **UF2 (drag-and-drop)** | Подключить плату в режиме UF2 (двойной тап по кнопке reset), скопировать `.uf2` на появившийся диск |
| **pio run -t upload** | Через PlatformIO (nrfutil) |
| **через J-Link** | `pio run -e Xiao_nrf52_companion_radio_usb -t upload --upload-port jlink` |
| **OTA по BLE** | Через приложение Adafruit Bluefruit (если собран `_ble` вариант) |

### 7.5 Если HT-RA62 подключен к другой плате

Найдите в `variants/` свою плату или создайте свою. Для HT-RA62 везде одинаковые настройки SX1262:

```cpp
#define SX126X_DIO2_AS_RF_SWITCH   1
#define SX126X_DIO3_TCXO_VOLTAGE   1.8
#define SX126X_CURRENT_LIMIT       140
#define SX126X_RX_BOOSTED_GAIN     1
```

Пины SPI (SCK, MOSI, MISO) общие с остальной периферией. NSS, DIO1, BUSY, RESET — назначаются индивидуально.

### 7.6 Альтернативные платформы с nRF52840

Если HT-RA62 уже впаян в готовую плату — проверьте `variants/`, возможно ваша плата уже там:

| Плата | Вариант | Пример env |
|-------|---------|------------|
| RAK4631 WisBlock | `rak4631` | `env:RAK_4631_companion_radio_ble` |
| Nologo ProMicro nRF52840 | `promicro` | `env:ProMicro_repeater` |
| Nano G2 Ultra | `nano_g2_ultra` | `env:Nano_G2_Ultra_companion_radio_ble` |
| RAK3401 (1W) | `rak3401` | `env:RAK_3401_repeater` |

Список всех nRF52-вариантов — в `variants/`.

## 8. Структура проекта (кратко)

```
MeshCore/
├── src/                          # ядро библиотеки
│   ├── Mesh.h / .cpp             # роутинг, диспетчеризация payload-типов
│   ├── Packet.h / .cpp           # формат пакета
│   ├── Dispatcher.h / .cpp       # планировщик радио
│   └── helpers/
│       └── BaseChatMesh.h/.cpp   # чат-абстракция (родительский класс)
├── examples/
│   └── companion_radio/          # ТО, ЧТО МЫ МОДИФИЦИРУЕМ
│       ├── MyMesh.h / .cpp       # основной класс
│       ├── main.cpp              # точка входа
│       └── ...
└── platformio.ini                # конфиг сборки
```

## 9. Как это работает (кратко)

1. Узел-отправитель знает публичный ключ устройства с реле (контакт добавлен через advertise)
2. Он отправляет `sendMessage(recipient, timestamp, 0, "on1234", ...)`
3. Пакет шифруется AES128+HMAC, летит по mesh (flood routing)
4. Устройство-исполнитель получает, расшифровывает, `BaseChatMesh` вызывает `onMessageRecv()`
5. Мы проверяем текст, управляем реле/читаем температуру и шлём ответ
6. Ответ тоже шифрованный, идёт по обратному пути
