USB-C Wi-Fi/BLE Sensor Design


Design a control panel schematic for a Boric Acid Slurry Automatic Measurement System. Please represent the PLC and external devices using terminal headers or generic IC blocks if specific parts are unavailable. Add text notes for wire colors: Black(AC L), Blue(AC N / DC 0V), Red(DC +24V), Yellow(Signals).
  1. Power Supply:
  • Add a 220V AC input block.
  • Add an AC/DC SMPS (220V AC to 24V DC).
  1. Inputs (24V DC, Source Input logic):
  • Create 4 input paths powered by +24V.
  • X0: Connected via a Normally Open (NO) Pushbutton (Start).
  • X1: Connected via a NO Pushbutton (Stop).
  • X2: Connected via a NO Relay contact (representing Temp Controller 40°C).
  • X3: Connected via a NO Relay contact (representing Temp Controller 43°C).
  • Route all inputs to a generic block representing 'PLC Inputs'.
  1. Outputs (24V DC, Sink Output logic - switching to GND):
  • Create a block representing 'PLC Outputs' (Y0 to Y3).
  • Y0: Connect to the negative control input of an SSR. The load side of this SSR switches 220V AC for 'P-101 Pump'.
  • Y1: Connect to the negative coil of a standard DC Relay. The NO contact of this relay switches +24V DC for 'P-102 DC Pump'.
  • Y2: Connect to the negative control input of an SSR. The load side switches 220V AC for 'V-1 Main Pump'.
  • Y3: Connect to the negative coil of a DC Relay for an Alarm.
  1. Communication:
  • Add an RS-485 transceiver or a generic 2-pin header labeled 'RS-485 RDA/RDB for Turbidity Sensor'.
I’ll add a separate control-panel schematic block for the boric acid slurry measurement system, using terminal headers/generic blocks for the PLC, SMPS, SSRs, relays, pumps, alarm, and RS‑485 sensor wiring. I’ll keep the existing design intact unless you explicitly ask me to replace it.
Added the Boric Acid Slurry control-panel schematic as a separate subsystem without removing the existing sensor-node design.
Completed:
  • 220 VAC input and 220 VAC → 24 VDC SMPS.
  • PLC input block with X0 Start, X1 Stop, X2 Temp 40 °C, X3 Temp 43 °C using +24 V source-input logic.
  • PLC output block with Y0–Y3 sink-output logic for SSRs/relays, P-101, P-102, V-1, and alarm.
  • RS-485 RDA/RDB terminal for turbidity sensor.
  • Wire-color notes documented in the project file: Boric Acid Slurry Automatic Measurement System — Control Panel Wiring.
Electrical review for the new control-panel wiring returned no matching ERC errors/warnings. Note: final SSR/relay/contact ratings should be checked against real pump current, inrush, enclosure, fusing, and local electrical safety requirements before panel build.
Add protection devices
Add field terminals
Check load ratings
Run full review
Create control BOM

온도조절기
K_P102 NO - P102 +
SSR_P101 AC_B - P101 +
PLC의 'X0' 단자
TC43_CONTACT 2 - SSR_P101 +DC
P-102(DC 펌프)의 (-) 단자
V-1(DC 솔레노이드 밸브)의 (-) 단자
PLC 출력부의 'COM' 단자 (COM1, COM2 등 사용하는 모든 COM)
온도조절기(SU-103SR3) OUT1의 COM 단자
J_AC_IN P2 - PS1 AC/N
계측펌프용 SSR의 제어 입력(+) 3번 단자
온도조절기 OUT1의 NO(A접점) 단자
정지 버튼의 출력(A접점) 단자
P-101(AC 순환 펌프)의 L선 입력 단자
PLC_OUT 4 - K_P102 COIL_2
P-101(AC 순환 펌프) 제어용 'DC to AC SSR'의 부하(Load) 측 1번 단자
CP_RS485 -
V-1(DC 솔레노이드 밸브)의 (+) 단자
(메인 전원 입력 )에서 시작. AC/L
1번 릴레이의 COM 단자
CP_RS485_RDB_BLUE
PLC의 'X1' 단자
PLC의 'Y0' 단자
CP_RS485+
J_AC_IN P2 - PS1 AC/N
J_AC_IN P2 - PS1 AC/N
히터의 N선
SMPS '+V' 단자
시작 버튼 스위치의 입력(COM) 단자
PLC의 'X2' 단자
지 버튼 스위치의 입력(COM) 단자
솔배 제어용 중간 릴레이의 코일(+) 단자
J_AC_IN P1 - PS1 AC/L
1번 릴레이의 코일(-) 단자
2번 릴레이의 NO 단자
2번 릴레이의 코일(-) 단자
PLC의 'Y2' 단자
계측펌프용 코일의 (-) 단자
P-101용 SSR의 제어 입력(-) 4번 단자
s/s
순환수조제어용 중간 릴레이의 코일(+) 단자
온도조절기 OUT1의 NO(A접점) 단자
시작 버튼의 출력(A접점) 단자
PLC의 'Y1' 단자
SMPS '-V' 단자
PLC의 'X3' 단자
PLC_OUT 5 - SSR_V1 -DC
온도조절기(SU-103SR3) OUT2의 COM 단자
CP_RS485_RDA_YELLOW
히터의 L
1번 릴레이의 NO 단자
PLC_IN
솔배 제어용 릴레이
RS 485
PLC_OUT
J_RS485
K2
J_AC_IN
PB_START 스위치
계측펌프
히터
Resistance
500 Ω
PB_STOP
R1
Resistance
500 Ω
순환펌프
dc 솔배
SSR_순환펌프
터미널 DC-V
Pin Number
2
터미널
Pin Number
1
SMPS
Firmware Starter — ESP32-C3-WROOM-02-N4
Platform & Toolchain
  • MCU/module: ESP32-C3-WROOM-02-N4
  • Framework: Arduino on PlatformIO
  • Sensor: Sensirion SHT40-AD1B-R3, I2C address 0x44
  • USB programming/debug: native ESP32-C3 USB Serial/JTAG on IO18/IO19
Pin Mapping

Table


FunctionGPIO / PinConnected ToDirectionNotes
I2C_SDAGPIO4U4 SDA, R_SDA 4.7 kΩ pull-upBidirectionalSHT40 data line
I2C_SCLGPIO5U4 SCL, R_SCL 4.7 kΩ pull-upOutputSHT40 clock line
STATUS_LEDGPIO10R_LED then LED1OutputActive high LED
USB_D_NGPIO18J1 DN1/DN2 through ESD D1USBNative USB D-
USB_D_PGPIO19J1 DP1/DP2 through ESD D1USBNative USB D+
ESP_BOOT_IO9GPIO9Boot button to GND, 10 kΩ pull-upInput/strapHold BOOT while resetting to enter download mode
ESP_ENENReset button, 10 kΩ pull-up, 1 µF to GNDResetPull low to reset
platformio.ini

Ini


[env:esp32-c3-devkitm-1]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
monitor_speed = 115200
upload_speed = 460800
build_flags =
    -D ARDUINO_USB_MODE=1
    -D ARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
    adafruit/Adafruit SHT4x Library@^1.0.5
    h2zero/NimBLE-Arduino@^1.4.2
Complete Firmware Source — src/main.cpp

Cpp


#include <Arduino.h>
#include <Wire.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_SHT4x.h>
#include <NimBLEDevice.h>

// Pin definitions from schematic
#define I2C_SDA_PIN      4
#define I2C_SCL_PIN      5
#define STATUS_LED_PIN   10
#define BOOT_BUTTON_PIN  9

// SHT40 default I2C address is 0x44. The Adafruit driver handles this internally.
#define SENSOR_READ_INTERVAL_MS 10000UL
#define WIFI_RETRY_INTERVAL_MS  30000UL

const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* HTTP_ENDPOINT = "http://example.local/environment";

Adafruit_SHT4x sht4;
unsigned long lastSensorRead = 0;
unsigned long lastWifiAttempt = 0;
bool sensorReady = false;

NimBLEServer* bleServer = nullptr;
NimBLECharacteristic* envCharacteristic = nullptr;

static void setStatusLed(bool on) {
  digitalWrite(STATUS_LED_PIN, on ? HIGH : LOW);
}

static void initI2CAndSensor() {
  Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN, 400000);

  sensorReady = sht4.begin(&Wire);
  if (!sensorReady) {
    Serial.println("ERROR: SHT40 not found on I2C address 0x44");
    return;
  }

  sht4.setPrecision(SHT4X_HIGH_PRECISION);
  sht4.setHeater(SHT4X_NO_HEATER);  // Keep heater off for low-power normal operation.
  Serial.println("SHT40 initialized");
}

static void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.setSleep(true);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  lastWifiAttempt = millis();
  Serial.print("Connecting to WiFi");
}

static void maintainWiFi() {
  if (WiFi.status() == WL_CONNECTED) {
    return;
  }

  unsigned long now = millis();
  if (now - lastWifiAttempt >= WIFI_RETRY_INTERVAL_MS) {
    Serial.println("Retrying WiFi connection");
    WiFi.disconnect(true);
    delay(50);
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    lastWifiAttempt = now;
  }
}

static void initBLE() {
  NimBLEDevice::init("EnvNode-C3");
  NimBLEDevice::setPower(ESP_PWR_LVL_N0);  // Conservative BLE TX power for consumer node.

  bleServer = NimBLEDevice::createServer();
  NimBLEService* service = bleServer->createService("181A");  // Environmental Sensing service

  envCharacteristic = service->createCharacteristic(
      "2A6E",  // Temperature characteristic UUID
      NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);

  envCharacteristic->setValue("0.00 C, 0.00 %RH");
  service->start();

  NimBLEAdvertising* adv = NimBLEDevice::getAdvertising();
  adv->addServiceUUID("181A");
  adv->setScanResponse(true);
  adv->start();

  Serial.println("BLE environmental service advertising");
}

static bool readSHT40(float& temperatureC, float& humidityPercent) {
  if (!sensorReady) {
    return false;
  }

  sensors_event_t humidity;
  sensors_event_t temp;
  bool ok = sht4.getEvent(&humidity, &temp);
  if (!ok) {
    Serial.println("ERROR: SHT40 read failed");
    return false;
  }

  temperatureC = temp.temperature;
  humidityPercent = humidity.relative_humidity;
  return true;
}

static void publishWiFi(float temperatureC, float humidityPercent) {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi not connected; skipping HTTP publish");
    return;
  }

  HTTPClient http;
  http.begin(HTTP_ENDPOINT);
  http.addHeader("Content-Type", "application/json");

  String payload = "{\"temperature_c\":" + String(temperatureC, 2) +
                   ",\"humidity_percent\":" + String(humidityPercent, 2) + "}";

  int code = http.POST(payload);
  Serial.printf("HTTP POST %d: %s\n", code, payload.c_str());
  http.end();
}

static void publishBLE(float temperatureC, float humidityPercent) {
  if (envCharacteristic == nullptr) {
    return;
  }

  char payload[48];
  snprintf(payload, sizeof(payload), "%.2f C, %.2f %%RH", temperatureC, humidityPercent);
  envCharacteristic->setValue((uint8_t*)payload, strlen(payload));
  envCharacteristic->notify();
}

void setup() {
  pinMode(STATUS_LED_PIN, OUTPUT);
  pinMode(BOOT_BUTTON_PIN, INPUT_PULLUP);
  setStatusLed(false);

  Serial.begin(115200);
  delay(500);
  Serial.println("USB-C WiFi/BLE Environmental Sensor Node booting");

  initI2CAndSensor();
  initBLE();
  initWiFi();
}

void loop() {
  maintainWiFi();

  unsigned long now = millis();
  if (now - lastSensorRead >= SENSOR_READ_INTERVAL_MS) {
    lastSensorRead = now;

    float temperatureC = 0.0f;
    float humidityPercent = 0.0f;
    if (readSHT40(temperatureC, humidityPercent)) {
      setStatusLed(true);
      Serial.printf("T=%.2f C, RH=%.2f %%\n", temperatureC, humidityPercent);
      publishBLE(temperatureC, humidityPercent);
      publishWiFi(temperatureC, humidityPercent);
      delay(25);
      setStatusLed(false);
    } else {
      for (int i = 0; i < 3; ++i) {
        setStatusLed(true);
        delay(80);
        setStatusLed(false);
        delay(80);
      }
    }
  }

  delay(10);
}
Build, Flash, and Monitor

Bash


pio run
pio run -t upload
pio device monitor
Bootloader Entry
  1. Hold SW_BOOT.
  2. Press and release SW_RESET.
  3. Release SW_BOOT.
  4. Run pio run -t upload.
Low-Power Notes
  • Keep the SHT40 heater disabled for normal environmental monitoring.
  • Increase SENSOR_READ_INTERVAL_MS to reduce Wi-Fi activity.
  • For production battery-derived variants, use deep sleep and wake periodically; this USB-C version keeps USB/Wi-Fi services active by default.
  • Platform & Toolchain

  • Pin Mapping

  • `platformio.ini`

  • Complete Firmware Source — `src/main.cpp`

  • Build, Flash, and Monitor

  • Bootloader Entry

  • Low-Power Notes