New afvalwijzer using Home Assistant

New version of :

New schematic using ESPHOME and has reset button (pressing the lid).
(Resets the LED when you’ve put the trash at the street curb.)

Above, a simplified version. I’m using 4 ws2812 leds now.

ESPHOME code:

esphome:
  name: afvalwemos
  friendly_name: AfvalWemos
  on_boot:
    priority: 800
    then:
    - delay: 1s
    - light.turn_off: main_leds

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "bT76oR8vOxxxxxxxxxxxxxxxxxxxxxxxxQbyjY6M="

ota:
  - platform: esphome
    password: "c1dbxxxxxxxxxxxxxxxxxxxxxxxxxx36e75"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Afvalwemos Fallback Hotspot"
    password: "vVxxxxxxxxxxxxxxaw"

captive_portal:

# LED strip definition
light:
  - platform: neopixelbus
    type: RGB
    variant: WS2812
    pin: D5
    num_leds: 4
    name: "All LEDs"
    id: main_leds
    restore_mode: ALWAYS_OFF   # ensures all LEDs start off


  # Individual LED partitions
  - platform: partition
    name: "LED 1"
    segments:
      - id: main_leds
        from: 0
        to: 0

  - platform: partition
    name: "LED 2"
    segments:
      - id: main_leds
        from: 1
        to: 1

  - platform: partition
    name: "LED 3"
    segments:
      - id: main_leds
        from: 2
        to: 2

  - platform: partition
    name: "LED 4"
    segments:
      - id: main_leds
        from: 3
        to: 3


# Physical button on D6 to turn off all LEDs
binary_sensor:
  - platform: gpio
    pin:
      number: D6
      mode: INPUT_PULLUP
      inverted: True
    name: "All Off Button"
    on_press:
      - logger.log: "Button pressed — turning all LEDs OFF"
      - light.turn_off: main_leds

Home Assistant automation:

alias: Afvalwijzer Plastic
description: Afvalwijzer leds
triggers:
  - at: "18:00:00"
    trigger: time
conditions:
  - condition: template
    value_template: >
      {% set raw = states('sensor.gad_pmd') %} {% if raw not in ['unknown',
      'unavailable', 'none', ''] %}
        {% set clean = raw.replace('Tomorrow, ', '').replace('Today, ', '').strip() %}
        {% set parts = clean.split(', ') %}
        {% set date_part = parts[-1] if parts|length > 1 else clean %}
        {% set pmd_date = strptime(date_part, '%d-%m-%Y').date() %}
        {% set tomorrow = (now().date() + timedelta(days=1)) %}
        {{ pmd_date == tomorrow }}
      {% else %}
        false
      {% endif %}
actions:
  - action: light.turn_on
    target:
      entity_id: light.afvalwemos_led_3
    data:
      rgb_color:
        - 236
        - 199
        - 14
mode: single

Easy cheap touch light

Remember those expensive touch lights you can buy?

This is a less than 5 euro version.

Warning : Some tricks I used

  • Using D5 as GND (I didn’t want to splice GND Wire.)
  • Using PWM for dimming
  • Using 5V led, use resistor if using a generic LED (220ohm)

TTP223 sensors are only a few cents!
And react even without touching (< 5mm)
So, you can build this in a case or behind fabric!

NOTE: If you are using an ESP32 you can configure a pin as touch!!!
No TTP223 needed.
But ESP32 are more expensive as Wemos mini.

Code:

#define TOUCH_PIN D2 // My video has D7
#define LED_PIN   D6
#define FAKE_GND D5

// Brightness steps (0 = off, 255 = full bright)
int brightnessLevels[] = {0, 25, 125, 255};
int currentLevel = 0;
bool lastTouchState = LOW;

void setup() {
  
  pinMode(TOUCH_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  pinMode(FAKE_GND, OUTPUT);

  digitalWrite(FAKE_GND, LOW);  
  analogWrite(LED_PIN, brightnessLevels[currentLevel]);  // start OFF
}

void loop() {
  bool touchState = digitalRead(TOUCH_PIN);

    if (touchState == HIGH && lastTouchState == LOW) {
      // Advance brightness step
      currentLevel = (currentLevel + 1) % 4;  // 0-3 steps
      int pwmValue = brightnessLevels[currentLevel];
      analogWrite(LED_PIN, pwmValue);
    }

  lastTouchState = touchState;
}

Dim levels less obvious on recording, but you can change the levels in the code!

DIY Garden Lights.

We are planning to redo our garden. And I am making a water and light plan for it.

I thought I could do it myself using 12V and RS485/Modbus.

So these are my plans. (NOTE, this is a work in progress)

I’m going to put 4-wire ground cable in our garden, and a RS485/Modbus master controller in my shed.
4 Wires will have 12V low voltage, ground and RS485 A/B wires.
This way I can control till 64 devices on a single cable.

Below, a USB stick to connect the RS485 cables to a Raspberry Pi?
Software is probably going to be a NodeRed instance connected to Home Assistant.

On/Off lights using a RS485 board and relay. These can be bought on a single PCB and can control 220V. I am probably going to use generic outside lamps and refit them for 12V led or 220v, with those RS485 controllers.

The above left part will be encased in resin or alike.
Right PCB is for testing only.

For dimming RGB lights, I made the below design.

12V to 5V using a 7805, RS485 8pin DIL/DIP and a ATTiny85 8pin DIL/DIP. Plus a 4×4 RGB Matrix.
These also encased in resin.

More information on the ATTiny85 and programmer can be found here:

Modbus using NodeRed (I’ve used this to control my RD6006 Lab Power Supply)

5 sensor Flame detector

December is coming, time for candles.

The plan is to make a flame sensor, with in combination with my presence sensor will alert me when we leave the room and candles are on, give us a notification.

Above is the schematic. A Wemos mini (left over from another project), an analog multiplexer and a cheap 5 times flame detector.
There is a potentiometer on this board to change the sensitivity.

Search “Infrared Ir Flame Sensor Detector Fire Detection Module 5 Channel” on Aliexpress. These are 1 euro.

Presence sensor:

Here is some Arduino code.

#define MUX_A D5
#define MUX_B D6
#define MUX_C D7
#define ENABLE D1

#define ANALOG_INPUT A0


void setup() {
    Serial.begin(9600);

  //Define output pins for Mux
  pinMode(MUX_A, OUTPUT);
  pinMode(MUX_B, OUTPUT);     
  pinMode(MUX_C, OUTPUT);     
  pinMode(ENABLE, OUTPUT);     
  digitalWrite(ENABLE, LOW); // No need to switch, can be permanenty low
  
}

void changeMux(int c, int b, int a) {
  digitalWrite(MUX_A, a);
  digitalWrite(MUX_B, b);
  digitalWrite(MUX_C, c);
}

void loop() {
  float value;
  
  
  changeMux(LOW, LOW, HIGH);
  value = analogRead(ANALOG_INPUT); //Value of the sensor connected Option 1 pin of Mux
  Serial.print("Variable_1:");
  Serial.print(value);
  Serial.print(",");

  changeMux(LOW, HIGH, LOW);
  value = analogRead(ANALOG_INPUT); //Value of the sensor connected Option 2 pin of Mux
  Serial.print("Variable_2:");
  Serial.print(value);
  Serial.print(",");

  changeMux(LOW, HIGH, HIGH);
  value = analogRead(ANALOG_INPUT); //Value of the sensor connected Option 3 pin of Mux
  Serial.print("Variable_3:");
  Serial.print(value);
  Serial.print(",");

  changeMux(HIGH, LOW, LOW);
  value = analogRead(ANALOG_INPUT); //Value of the sensor connected Option 4 pin of Mux
  Serial.print("Variable_4:");
  Serial.print(value);
  Serial.print(",");

  changeMux(HIGH, LOW, HIGH);
  value = analogRead(ANALOG_INPUT); //Value of the sensor connected Option 5 pin of Mux
  Serial.print("Variable_5:");
  Serial.println(value);
}

ESPHOME Code

esphome:
  name: flamedetector
  friendly_name: FlameDetector
  on_boot:
    priority: 600
    then:
      - switch.turn_off: enable 

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "BMHbLdN6Rxxxxxxxxxxxxxxxxxxxxv0LE="

ota:
  - platform: esphome
    password: "780fe0xxxxxxxxxxxxxxxxxxxxx7859"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Flamedetector Fallback Hotspot"
    password: "cm1xxxxxxxxxxxxNX"

captive_portal:

switch:
  - platform: gpio
    id: enable
    pin:
      number: D1

cd74hc4067:
  - id: cd74hc4067_1
    pin_s0: D5
    pin_s1: D6
    pin_s2: D7
    pin_s3: D2

globals:
  - id: last_flame_state
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: trigger_on
    type: bool
    restore_value: no
    initial_value: 'false'

sensor:
  - platform: adc
    id: adc_sensor
    pin: A0
    name: flameanalog
    update_interval: 10s
  - platform: cd74hc4067
    id: flame_1_1
    name: flame_1_1
    number: 1
    sensor: adc_sensor
    update_interval: 10s
  - platform: cd74hc4067
    id: flame_1_2
    name: flame_1_2
    number: 2
    sensor: adc_sensor
    update_interval: 10s
  - platform: cd74hc4067
    id: flame_1_3
    name: flame_1_3
    number: 3
    sensor: adc_sensor
    update_interval: 10s
  - platform: cd74hc4067
    id: flame_1_4
    name: flame_1_4
    number: 4
    sensor: adc_sensor
    update_interval: 10s
  - platform: cd74hc4067
    id: flame_1_5
    name: flame_1_5
    number: 5
    sensor: adc_sensor
    update_interval: 10s


interval:
  - interval: 10s
    then:
      - lambda: |-
          const float threshold = 0.01;
          bool any_above =
            id(flame_1_1).state > threshold ||
            id(flame_1_2).state > threshold ||
            id(flame_1_3).state > threshold ||
            id(flame_1_4).state > threshold ||
            id(flame_1_5).state > threshold;

          // Store the result
          if (any_above != id(last_flame_state)) {
            id(last_flame_state) = any_above;
            if (any_above) {
              ESP_LOGI("flame_check", "Flame detected (turning ON)");
              id(trigger_on) = true;
            } else {
              ESP_LOGI("flame_check", "No flame detected (turning OFF)");
              id(trigger_on) = false;
            }
          }

  - interval: 1s
    then:
      - if:
          condition:
            lambda: 'return id(trigger_on);'
          then:
            - homeassistant.service:
                service: homeassistant.turn_on
                data:
                  entity_id: input_boolean.testtoggle
          else:
            - homeassistant.service:
                service: homeassistant.turn_off
                data:
                  entity_id: input_boolean.testtoggle

C64 ROM switcher, Hidden cam viewer, Motorized fader pot and PCB sponsor

Lol, got an email from a PCB sponsor!

Deeply impressed by your blog content which means a lot to electronic enthusiasts.
I'd like to sponsor your project by providing free PCB prototyping,

ROM SWITCHER

I made a rom switcher in the past.
Now I’m using an Arduino to switch Kernal and Character rom.
(Partly idea from Adrian)

Where the F* is my schematic. Ah here it is.

Above right picture:

  • Tactile button (emulates restore key)
  • Red led – reset
  • Yellow led – Exrom
  • Blue leds, Address lines select ROM part in 27512 EPROM
  • Green leds, Address lines select ROM part Character ROM

Motorized Fader Potentiometer

I don’t trust some B&B’s so I made a camera detector.
(I always scan the wifi and Access Points)
This one lets you know if there are IR enabled camera’s.
(Night vision)

Picture 1:

  • 1 = org camera module, IR filter is hard to remove. (See pink color)
  • 2 = other module, IR filter is at bottom
  • 3 = IR Filter, I removed this.

Picture 2:

IR light blast from a “hidden” camera. (I need to adjust focus of lens)

Three display C64 audio monitor

While I made this for my Commodore C64, it is applicable for many things.

It started with some cheap displays from Ali, and some leftover Wemos D1 from my Pressure Lab project.

I Started measuring the audio output from sound devices and from my C64.
I soon discovered that I needed some way to get the offset and amplification correct for the analogue input of a Wemos. (0-3v3)

So a little op-amp circuit was born, but not without some struggles.
I forgot many things about amplifiers. It was one of the first school books I got rid of. (Sorry mister Rafaela)

After searching the internet and posting a question on Reddit I ended up with the following.

R1 and R2 are 100M. The potentiometer P1 allows me to set the offset.
R3 is 1M
C1 is 100nF to decouple the audio signal from the RCA.

R4 is 47K and C2 is 330nF (thanks tycho205)
Cimportant=1/(2πfR2)
where f is the lowest frequency of interest. In this case Cimportant should be about 330nF

LM324 is a quad amplifier, leftover from another project.
Note, the SINGLE RAIL power.

P2 potentiometer is 2M (leftover) and gives me a variable amplifying opportunity.


A = Audio input

B = Setting the offset with P1

C = Setting the amplification

Below input signal (note negative values) above amplified signal with offset!

The displays are 3 Wemos controllers with a cheap I2C display.
These are just fast enough to do FFT.

Analogue in is the output from the OP-amp offsetter ..

CODE

Needs cleaning up, and a better stabilize routine.

Signal generator and Midi progress

Yesterday I got my new signal generator (FY6900), my DIY version was missing functions.
Now I can test my op-amp schematic I’ve been posting about.

MIDI Controller

Next, for my YM2203 player, I wanted to make this Midi Controllable.
But I don’t have a Midi Controller which has enough knobs and keys.
Besides that, I thought it was cool to build my own.

  • Teensy 4.0 (because I needed multiple analogue inputs, I used another controller before, with an analogue multiplexer. But I wanted to use the easy method to use USB as midi also.
    The board will also have midi connectors, but not populated yet.
    So you can use both.
  • SSD1306 display (for now)
    Showing note being played and two potentiometer values.
  • Two potentiometers (for now) I can use these separately. But when pressing the last key on the key matrix, it will change the CC Channel of the first pot. (Using the value of the second)
  • 4×4 Matrix keyboard being read by a MCP23017 I2C 16-bit GPIO Expander. Both display and GPIO expander are on the same bus.

MCP23017 pinout

I used some pullups on : /RESET and GPA0-3
Pullups not needed on SDA/CLK because these are on the display board.

Midi control YM2203 and Analog AMP stuff

While watching TV, I drew some schematics for the YM2203 player.

For another project, I was researching the best way to get the voltage levels perfect for below analogue input.

(See the little red breadboard in the right picture above! )

Damn, I couldn’t do this stuff in school. Tried to forget it all … now I need it!

Top of this image shows what I want to accomplish. Audio or other input which has negative values also, convert to another voltage range to be read by analog read on an Wemos. These can only read 0-3v3

YM2203 – next part – Midi

I took yesterday’s setup and added polyphonic Midi.

Schematic same as previous post, just added a Midi Shield.

I can use my QY100 as midi keyboard. But playing midi files is also fun!

Because it isn’t using the right instrument and not all channels are being used.

I wanted to make a register replacer, which utilizes a sdcard reader and music dump to play songs.
But I think I’m going to make a full-blown Midi song player for the YM2203.

YM2203 Player

UPDATE: FM using the DAC is also working

At the hackercamp I mentioned a few posts ago, I met a guy who was into synths and we started talking.
We discovered we have much in common.

I showed him my AY-3-8910 player, but he had some other sound chips he wanted to play with.

After we found out which ones, I decided to buy some.
And last week I started building a player for it.

Ultimate goal is to make this midi enabled.

The chip in question is a YM2203 from Yamaha. It has three channels and can do FM sounds.

Today the first sounds! (2 channels)

  • Arduino UNO (clone)
  • YM2203
  • YM3014 DAC
  • LM324 Amplifier
  • 1Mhz crystal (that’s what I could find)

Below is the schematic, code will follow. (Needs a lot of cleanup)

I used A1 for reset signal, and have not used the complete amplifying part

I think I’m going to make some kind of library/class.
For easy programming.

FM via DAC

CODE FOR PSG (Programmable Sound Generator)
(FM code will follow)

// --- Pin definitions for Arduino Uno ---
#define YM_D0   2   // D0–D7 on Arduino D2–D9
#define YM_A0   10  // Address select
#define YM_WR   11  // Write
#define YM_RD   12  // Read
#define YM_CS   13  // Chip Select
#define YM_RST  A1  // Reset

// CLK is 1Mhz
#define CLK_FREQ  1000000UL

struct Note {
  uint16_t freq; // Hz
  uint16_t dur;  // ms
  uint16_t vol;  // ms
};

// --- Simple melody table (frequencies in Hz) ---
Note melody[] = {
  {440, 400, 15}, {494, 400, 15}, {523, 400, 15}, {587, 400, 15}, // A4, B4, C5, D5
  {659, 400, 15}, {698, 400, 15}, {784, 800, 15},             // E5, F5, G5
  {0, 400, 0} // rest
};

const int melodyLength = sizeof(melody) / sizeof(Note);

// --- Setup I/O pins for YM2203 ---
void setupPins() {
  pinMode(YM_CS, OUTPUT);
  pinMode(YM_WR, OUTPUT);
  pinMode(YM_RD, OUTPUT);
  pinMode(YM_A0, OUTPUT);
  pinMode(YM_RST, OUTPUT);

  for (int i = 0; i < 8; i++) {
    pinMode(YM_D0 + i, OUTPUT);
  }

  digitalWrite(YM_CS, HIGH);
  digitalWrite(YM_WR, HIGH);
  digitalWrite(YM_RD, HIGH);
  digitalWrite(YM_RST, HIGH);
}

// --- Put 8-bit value on D0–D7 bus ---
void setDataBus(uint8_t val) {
  for (int i = 0; i < 8; i++) {
    digitalWrite(YM_D0 + i, (val >> i) & 1);
  }
}

// --- Write register/data to YM2203 ---
void ymWrite(uint8_t reg, uint8_t val) {
  digitalWrite(YM_CS, LOW);

  // Send register address
  digitalWrite(YM_A0, LOW);
  setDataBus(reg);
  digitalWrite(YM_WR, LOW); delayMicroseconds(1);
  digitalWrite(YM_WR, HIGH);

  // Send data
  digitalWrite(YM_A0, HIGH);
  setDataBus(val);
  digitalWrite(YM_WR, LOW); delayMicroseconds(1);
  digitalWrite(YM_WR, HIGH);

  digitalWrite(YM_CS, HIGH);
}

// --- Set PSG Channel A frequency ---
void setChannelAFreq(uint16_t freq) {
  if (freq == 0) {  // rest
    ymWrite(0x08, 0x00); // volume 0 (mute)
    return;
  }

  // YM2203 PSG frequency formula: Fout = clock / (16 * N)
  // N = 12-bit value
  uint16_t N = CLK_FREQ / (16UL * freq);

  ymWrite(0x00, N & 0xFF);         // Freq LSB
  ymWrite(0x01, (N >> 8) & 0x0F);  // Freq MSB
}

// --- Set PSG Channel B frequency ---
void setChannelBFreq(uint16_t freq) {
  if (freq == 0) {  // rest
    ymWrite(0x09, 0x00); // volume 0 (mute)
    return;
  }

  // YM2203 PSG frequency formula: Fout = clock / (16 * N)
  // N = 12-bit value
  uint16_t N = CLK_FREQ / (16UL * freq);

  ymWrite(0x02, N & 0xFF);         // Freq LSB
  ymWrite(0x03, (N >> 8) & 0x0F);  // Freq MSB
}

// --- Set PSG Channel C frequency ---
void setChannelAFreq(uint16_t freq) {
  if (freq == 0) {  // rest
    ymWrite(0x0A, 0x00); // volume 0 (mute)
    return;
  }

  // YM2203 PSG frequency formula: Fout = clock / (16 * N)
  // N = 12-bit value
  uint16_t N = CLK_FREQ / (16UL * freq);

  ymWrite(0x04, N & 0xFF);         // Freq LSB
  ymWrite(0x05, (N >> 8) & 0x0F);  // Freq MSB
}

// --- Set PSG Channel A volume ---
void setChannelAVol(uint8_t vol) {
  ymWrite(0x08, vol);             
}
// --- Set PSG Channel B volume ---
void setChannelAVol(uint8_t vol) {
  ymWrite(0x09, vol);             
}
// --- Set PSG Channel C volume ---
void setChannelAVol(uint8_t vol) {
  ymWrite(0x0A, vol);             
}

// --- Arduino setup ---
void setup() {
  setupPins();

  // Reset YM2203
  digitalWrite(YM_RST, LOW);
  delay(100);
  digitalWrite(YM_RST, HIGH);
  delay(100);

  // Enable PSG Channel A tone, disable noise
  ymWrite(0x07, 0b11111110); // bit0=0 enables tone A
//  ymWrite(0x07, 0b11111101); // bit1=0 enables tone B
//  ymWrite(0x07, 0b11111011); // bit2=0 enables tone C
}

// --- Play melody in loop ---
void loop() {
  for (int i = 0; i < melodyLength; i++) {
    setChannelAFreq(melody[i].freq);
    setChannelAVol(melody[i].vol);
    delay(melody[i].dur);
  }
}

"If something is worth doing, it's worth overdoing."