Category Archives: Computer

Several things in progress, help me if you can.

I used MCE to control some Windows VMs and programs running in it in the past. (Below link and a web interface engine which on the backend converted BWW/BMW (bagpipe music files) to PDF automated comes to mind)

Now, I implemented this:

https://iotlink.gitlab.io/

Controlling a Windows VM using MQTT, very nice!
(Use HA mqtt or mosquitto_pub in bash)

Question: anyone got a better solution to control programs within a VM? Let me know.

Next:

I’m creating a new case for my Wemos, LCD16x2, button, Led, Buzzer project (see other post)

I’m redesigning my previous case in blender.

But I really miss something like a generator function for different cases, like the one I made using Openscad.
Question: Anyone know a tool/add-on to generate cases?
I used a model of a wemos to get the usb connector/screw holes in place.

My spotify rfid case I will create using wooden lasercut cutouts.
https://www.henriaanstoot.nl/2024/03/06/revisiting-the-spotify-cube/

Next one:

In the past, I’ve controlled some blender lights using python and MQTT. But now I’m trying to control it using DMX.

Example of lighting in our living using mock-up couch and tables.

I found a cool add-on called Blender-DMX.
(B.t.w. wled can also use DMX)

Looks cool but, can I make a floorplan with this?

Blender add-on configuration

In Home Assistant I used a HACS add-on called : Art-net LED Lighting for DMX

Configuration can be done in configuration.yaml

light:
- platform: artnet_led
  host: BLENDERHOSTIP                   # IP of Art-Net Node
  max_fps: 25                           
  refresh_every: 0                      # Resend values if no fades are running every x seconds, 0 disables automatic refresh
  node_type: artnet-direct              # Which protocol to use
  universes:                            # Support for multiple universes
    1:                                  # .Nr of Universe (see configuration of your Art-Net Node)
      send_partial_universe: True       # Only send the universe which contains data
      devices:
        - channel: 1                    # first channel of dmx dimmer
          name: dmx_dimmer_rgbw         # name
          type: rgbw                    # type
          transition: 1                 # default duration of fades in sec. 
          channel_size: 8bit            # width of the channel sent to DMX device, default "8bit", "16bit", "24bit" and "32bit" 
          channel_setup: Wrgb           # This is the magic to get colors correct

It works, but I’m not happy, anyone got a better solution?

And I have to check out GDTF profiles for fixtures.

At a later stage I’m going to 3d print a white floorplan about 1cm high, with LEDs and buttons. A floorplan you can hang on your wall.

Adding a VGA terminal to my 6502

Using a LilyGo TTGO ESP32 VGA32, I’m connecting my breadboard 6502 to a serial vga terminal with its own keyboard.

Due to a lot of moving around, new places, new homes I dumped a lot of terminal hardware.
Also are those old terminals too big and use too much power.

I’m going to use this DIY screen.
https://www.henriaanstoot.nl/2021/03/24/broken-or-slow-laptop-screen-still-works/

Using the Libraries from Fabrizio Di Vittorio, named FabGL, you can transform this device into a dumb terminal, game device, VIC-20, a 8086 pc and more.
There are even some projects to turn this into a C64.

But the main thing I want to do: A simple terminal.
(I probably revisit the other options again at a later stage)

My Wozmon bios has bare minimum support for serial communication, so i have to do some bitbanging.
(6502 is using a 6551 ACIA)

Sound from the ESP32 VGA board.

  • Chipset: TTGO Micro32 (ESP32 240Mhz dual core processor)
  • Flash memory: 4MB
  • SRAM: 520KB
  • Built-in Bluetooth
  • Built-in Wi-Fi
  • Supply voltage: 3.3V DC or 5V DC
  • GPIO voltage: 3.3V*
  • USB to serial converter: CP2102 or CH9102F (drivers)
  • VGA connection
  • PS/2: keyboard connection
  • PS/2: mouse connection
  • Built-in Li-ion/Li-Po battery charging circuit: TP4054 chip can charge up to 500mA

Home Assistant and Harmony Hub Scripts

I’ve got a Logitech Harmony Hub to IR control devices.

When adding this to your home assistant, you initially only get the Activities.

But I want to add single button presses.
I was going to re-visit my IR remote project.
(The IR blaster and the IR wemos, see previous posts)

Thanks to Duncan I had a second look at this solution

Check the files using the file editor.
Search for /homeassistant/harmony_xxxxxxxx.conf

It will show the Hub devices and their capabilities.

Short example below

{
    "Activities": {
        "-1": "PowerOff",
        "42652474": "Watch TV",
        "43054933": "Squeeze",
        "43054959": "Watch Netflix",
        "43072690": "Switch",
        "43073688": "Spotify",
        "43557114": "Kodi",
        "49494467": "Tv on",
        "52476284": "Boxon",
        "52476285": "Boxoff"
    },
    "Devices": {
        "Google Chromecast": {
            "commands": [],
            "id": "67134460"
        },
        "LG TV": {
            "commands": [
                "PowerOff",
                "PowerOn",
                "PowerToggle",
                ".",
                "-",
                "0",
 -----------8<----------------------------- SNIP SNAP
               "SportsMode"
            ],
            "id": "67134658"
        },
        "Onkyo AV Receiver": {
            "commands": [
                "PowerOff",
                "PowerOn",
 -----------8<----------------------------- SNIP SNAP
                "VolumeLevelUp5Step"
            ],
            "id": "67134459"
        },
        "arcadyan DVR": {
            "commands": [
                "PowerToggle",
 -----------8<----------------------------- SNIP SNAP
                "TV"
            ],
            "id": "67134775"
        }
    }
}

Lets create a Script for this

See the IDs above to refer to commands below.

alias: Netflix
sequence:
  - service: remote.send_command
    target:
      device_id: 7e82a825decabedbc98a0b5ce2ac5d78
    data:
      num_repeats: 1
      delay_secs: 0.4
      hold_secs: 1.2
      command: PowerOn
      device: "67134658"
  - service: remote.send_command
    metadata: {}
    data:
      num_repeats: 1
      delay_secs: 0.4
      hold_secs: 0
      command: InputStb/Dvr
      device: "67134459"
    target:
      device_id: 7e82a825decabedbc98a0b5ce2ac5d78
  - service: remote.send_command
    metadata: {}
    data:
      num_repeats: 1
      delay_secs: 0.4
      hold_secs: 0
      command: Netflix
      device: "67134658"
    target:
      device_id: 7e82a825decabedbc98a0b5ce2ac5d78
mode: single

Add these scripts to buttons

type: entities
entities:
  - script.allmediaoff
  - script.netflix
  - script.tvon

Some nice google matching tests.

Step one, change your main DNS resolver to that one from your provider or 1.1.1.1 (cloudflare)

Goto https://www.hawking.org.uk/ in your browser

Check youtube, facebook and more.

Set you DNS to 8.8.8.8 (google)

Do the same (even in a incognito browser).

I haven’t seen a Hawking recommendation on YT for ages, I just checked a website with information on another machine.
And my YT stream showed …. Stephen Hawking!

Kodi camera stream push playlist

Below is a solution when you want to stream IP camera’s in Kodi/Libreelec .

You can push these commands using Nodered, Bash script or whatever.

First make some camera scripts in your profile directory.

Examples:

# Kodi on Linux/Raspberry
# Place a file cam1.m3u in .kodi/userdata/profiles/(kodiprofile)/playlists/video/
rtsp://admin:secretpass@192.168.1.123:88/videoMain

#and another one in cam2.m3u (another example mjpeg example)
http://192.168.1.124:8000/stream.mjpg

#For windows it is in
C:\Users\(Username)\AppData\Roaming\Kodi\userdata\profiles\(kodiprofile)\playlists\video

Enable http access in Kodi and run the playlist using curl

curl -i -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"Player.Open","params":{"options":{"shuffled":false,"repeat":"off"},"item":{"file":"special://profile/playlists/video/cam2.m3u"}},"id":"1"}' http://KODISERVERIP:8080/jsonrpc

A bash loop script

while true; do
curl -i -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"Player.Open","params":{"options":{"shuffled":false,"repeat":"off"},"item":{"file":"special://profile/playlists/video/cam1.m3u"}},"id":"1"}' http://KODISERVERIP:8080/jsonrpc
sleep 10
curl -i -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"Player.Open","params":{"options":{"shuffled":false,"repeat":"off"},"item":{"file":"special://profile/playlists/video/cam2.m3u"}},"id":"1"}' http://KODISERVERIP:8080/jsonrpc
sleep 5
done

Three channel mixer for ay-3-8910 is almost done.

At the back the 8 pin single channel lm368 amplifier.
At the front the 3 channel setup.
I still have to tweak the resistors, and potmeters.
Then I can make a permanent PCB, and figure out the connections to the 6502.

At the moment, the Arduino Nano is playing some real sound samples by using the registers of the sound chip.
The music is being played by sending the register dumps directly to the chip.

Much like i’ve been using SID register dumps to play songs in another project.

This is version 0.1 .. do not use.
If its wrong, or can do better please mail me.
Oh it needs a 1k resistor from the 20K’s to ground I think.

What to do when waiting for your ribs on the smoker. (Programming some python)

This time I used a rub with the following ingredients:
Seasalt, garlic, brown sugar, mustard seeds, paprica, cilantroseeds, black pepper, red pepper, oregano, thyme and cumin.

Doing a simple 3-2-1 smoke session, so .. what to do in dose 6 hours?

Lets make something using a Sense hat and Python.
Same HAT I used for my xmas ornament thingy in our tree.

  • Generate a large maze (80×80 for now)
  • Paint the maze using colors on the SenseHat
  • Read joystick movement and scroll the maze accordingly, keeping the player in the middle

Now I have to paint my ribs with BBQ sauce, and leave it in the smoker for yet another hour. (Nice glazing)

Next steps for the maze:

Use a better way to generate (reverse backtracking as I made for my other maze thing)

Wall collision detection is nearly completed.

Better placement “birth” of player in the maze.

# # # # # # # # # # # # # # # # # # # # 

# R D . . . . . R D . . . . R R D R D # 

# D L . . . . . U D . . . . U . R U D # 

# D . . . . R R U R D . . R U U L . D # 

# R D . . . U . . . R R D U . . U L D # 

# . R D R R U . . . . . D U . . . U L # 

# . . D U L . . . . . D L U . . . . . # 

# . . R R U . . . . . R R U . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# . . . . . . . . . . . . . . . . . . # 

# # # # # # # # # # # # # # # # # # # # 

Big media button V2

Back in 2019 I made a volume/mute button using an ATtiny85.
(Digispark/trinkey thingy)

Same device as my password paster

It’s USB connection is perfect for this password paste thingy, but not for a big button like this. (even with a ugly usb extending cable)

2019 Version using digispark ATtiny85

Button is 3D printed (found on yeggi)

For my big battlestation i’m using:

The old way of flashing using Arduino IDE (for digispark)

Install Boards using : preferences, add board URL
http://digistump.com/package_digistump_index.json

Note: There being no regular USB device, you need to add some udev rules.
cat /etc/udev/rules.d/digispark.rules
SUBSYSTEM==”usb”, ATTR{idVendor}==”16d0″, ATTR{idProduct}==”0753″, MODE=”0660″, GROUP=”dialout”

When compiling and uploading the program, you get a message to plug in the device. See below screenshot.

Now the 2024 change.
Reason to change:

  • Want to have USB-C
  • Python to get a more flexible setup
  • I want to use more pins, so I can add LEDs and more buttons.
  • I wanted to play with my Waveshare RP2040 Zero.

This is the first setup, with same functionality as before.

Now I can add more stuff!

Putting the code on the RP2040-zero

Press boot button and insert into your pc.
Download uf2 file from here and save in RP2 drive.
https://circuitpython.org/board/waveshare_rp2040_zero/
Open Thonny, and configure interpreter to:

Download the zip file from https://github.com/adafruit/Adafruit_CircuitPython_HID
And copy only the subdirectory adafruit_hid to the drive in subdir lib

Open the file code.py from the device, and remove example hello world code.
Paste in the following code.

import rotaryio
import board
import time

import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode

but = digitalio.DigitalInOut(board.GP4)
but.direction = digitalio.Direction.INPUT
but.pull = digitalio.Pull.UP

cc = ConsumerControl( usb_hid.devices )

encoder = rotaryio.IncrementalEncoder(board.GP5, board.GP6)
last_position = 0
while True:
    position = encoder.position
    if int(last_position) < int(position):
        #print(position)
        command = ConsumerControlCode.VOLUME_DECREMENT
        cc.send(command)
    #last_position = position
    if int(last_position) > int(position):
        #print(position)
        command = ConsumerControlCode.VOLUME_INCREMENT
        cc.send(command)
    last_position = position
    if not but.value:
        command = ConsumerControlCode.MUTE
        cc.send(command)
        time.sleep(0.5)

Above code is the bare minimum, I’ll add more functionality soon.
(LEDs and more buttons)
Next and Previous Track and mode change.
From Audio to Navigation for example.

Well, learning every day

Some quotes I like to refer to:
https://www.henriaanstoot.nl/aboutme/

One of my websites was slow after the whole neighbourhood was without power for a few hours.
My lab using dual power, and a UPS went down for a few hours.

After that incident, one of my websites was slow, and it got worse with time.
But I never took the time to really look into this problem.
Until it was too much .. 8 seconds to TTFB

I’ve checked in the last month:

  • Hypervisors
  • Memory
  • CPU load
  • Docker instances
  • Reverse proxy
  • Bind DNS server
  • Iscsi storage
  • 10Gbps fibre connections
  • Database server
  • iotop latency

So, I was planning to rebuild my WordPress setup.
Meanwhile, let’s check some sites for information.

Then I came across WPCast on YouTube.
( How To Fix A Slow WordPress Site – WordPress Speed Optimization Tutorial )
Let’s watch this, while rebuilding my website.
All suggestions were in vain.

Until Query Monitor was mentioned.

I soon discovered that the resolving within my docker container was messed up!

2 http api call’s taking a long time.

Rebuild the docker container with my DNS nameserver and a second as fail back.

Fixed.

What did I learn, check all components!
Start close to the problem source.


Waveshare Epaper ESPHOME and Mqtt Notification over secure mqtt

UPDATE: AccessPoint on Arduino implemented with captive portal for Wifi Configuration

Got my Waveshare Epaper Cloud running on ESPHome

This is a Epaper display with a 2000mAh Lipo and a passive buzzer.
Running parts of my Smoker monitor.

Below a little movie clip with RTTTL sound notification.
(Send from Home Assistant)
B.t.w. RTTTL are those ringtones we used to have. (Ring Tone Text Transfer Language)

Sending from HA

Parts of the ESPHOME Yaml
NOTE: For the time, you need the time integration to get hours:minutes as a sensor!

esphome:
  name: epaperesp32

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
    - service: play_rtttl
      variables:
        song_str: string
      then:
        - rtttl.play:
            rtttl: !lambda 'return song_str;'

output:
  - platform: ledc
    pin: GPIO22
    id: rtttl_out

rtttl:
  output: rtttl_out
  on_finished_playback:
    - logger.log: 'Song ended!'

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxxxx"

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

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

captive_portal:

font:
  - file: 'fonts/tahoma.ttf'
    id: font1
    size: 16
  - file: 'fonts/tahoma.ttf'
    id: font2
    size: 32

sensor:
  - platform: adc
    pin: GPIO36
    name: "epaperesp32 Battery voltage"
    id: battery_voltage
    icon: mdi:battery
    device_class: voltage
    attenuation: auto 
    filters:
     - multiply: 3
    update_interval: 60s

text_sensor:
  - platform: homeassistant
    entity_id: sensor.bbqenv
    name: "mystate"
    id: mystate
    internal: true
  - platform: homeassistant
    entity_id: sensor.bbqcore
    name: "mystate1"
    id: mystate1
    internal: true
  - platform: homeassistant
    entity_id: sensor.time
    name: "mytime"
    id: mytime
    internal: true

spi:
  clk_pin: GPIO13
  mosi_pin: GPIO14

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO12
      inverted: true 
      mode:          
        input: true
        pullup: true
    name: "epaperesp32 button"
    filters:
      - delayed_on: 50ms
    on_press:
      - logger.log: "Button pressed"

display:
  - platform: waveshare_epaper
    cs_pin: GPIO15
    dc_pin: GPIO27
    busy_pin: GPIO25
    reset_pin: GPIO26
    model: 2.13in-ttgo
    rotation: 270
    full_update_every: 12
    update_interval: 10s
    lambda: |-
      it.print(0, 0, id(font2), "BBQ Meter V3");
      it.printf( 35, 32, id(font2), "%s", id(mystate).state.c_str());
      it.printf( 155, 32, id(font2), "%s", id(mystate1).state.c_str());

MQTT Notifier over Internet

This is part of a test where my friends and me can have notifications LEDs over the internet.

Using certificate parts from:
Controlling the led will be done using Mattermost webhooks, or slashcommand with custom scripting.
(Mattermost is my own hosted chat server)

I flashed a Wemos with below code:
(Rotary/display/button part removed.)

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <time.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>

#define encoderCLK 5   //D1
#define encoderDT 4    //D2
#define rgbled D4       //D4

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, rgbled, NEO_RGB + NEO_KHZ400);

int servoAngle = 0;
int crntCLK;
int prvsCLK;

String myString;
char ang[50];


#ifndef SECRET
const char ssid[] = "MYSSID";
const char pass[] = "MYPASS";

#define HOSTNAME "henrimqtt"

const char MQTT_HOST[] = "www.henriaanstoot.nl";
const int MQTT_PORT = 9883;
const char MQTT_USER[] = "xxxxxx"; // leave blank if no credentials used
const char MQTT_PASS[] = "xxxxxx"; // leave blank if no credentials used

const char MQTT_SUB_TOPIC[] = "notification/" HOSTNAME "/in";
const char MQTT_PUB_TOPIC[] = "notification/" HOSTNAME "/out";
const char MQTT_PUB_TOPIC_angle[] = "notification/" HOSTNAME "/send";

#ifdef CHECK_CA_ROOT
static const char digicert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIUXEEQRLHhYox8a95YiAYX/wQ/XeMwDQYJKoZIhvcNAQEN
//--------------- SNIP SNIP ... generated cert here
vht8GyCCgCH55Syvy9ls6gCyLjTT2rtllw==
-----END CERTIFICATE-----
)EOF";
    #endif

    #ifdef CHECK_PUB_KEY
    // Extracted by: openssl x509 -pubkey -noout -in ca.crt
    static const char pubkey[] PROGMEM = R"KEY(
    -----BEGIN PUBLIC KEY-----
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxx
    -----END PUBLIC KEY-----
    )KEY";
    #endif

    #ifdef CHECK_FINGERPRINT
        // Extracted by: openssl x509 -fingerprint -in ca.crt
    static const char fp[] PROGMEM = "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD";
    #endif
#endif

//////////////////////////////////////////////////////

#if (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_FINGERPRINT)) or (defined(CHECK_FINGERPRINT) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT) and defined(CHECK_FINGERPRINT))
  #error "cant have both CHECK_CA_ROOT and CHECK_PUB_KEY enabled"
#endif

BearSSL::WiFiClientSecure net;
PubSubClient client(net);

time_t now;
unsigned long lastMillis = 0;

void mqtt_connect()
{
  while (!client.connected()) {
    Serial.print("Time: ");
    Serial.print(ctime(&now));
    Serial.print("MQTT connecting ... ");
    if (client.connect(HOSTNAME, MQTT_USER, MQTT_PASS)) {
      Serial.println("connected.");
      client.subscribe(MQTT_SUB_TOPIC);
    } else {
      Serial.print("failed, status code =");
      Serial.print(client.state());
      Serial.println(". Try again in 5 seconds.");
      /* Wait 5 seconds before retrying */
      delay(5000);
    }
  }


}

void receivedCallback(char* topic, byte* payload, unsigned int length) {
    //  pixels.clear(); // Set all pixel colors to 'off'
 
  Serial.print("Received [");
  Serial.print(topic);
  Serial.print("]: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
if (!strncmp((char *)payload, "0", length)) {
       pixels.setPixelColor(0, pixels.Color(0, 0, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
if (!strncmp((char *)payload, "1", length)) {
       pixels.setPixelColor(0, pixels.Color(150, 0, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
if (!strncmp((char *)payload, "2", length)) {
       pixels.setPixelColor(0, pixels.Color(0, 0, 150));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
if (!strncmp((char *)payload, "3", length)) {
       pixels.setPixelColor(0, pixels.Color(0, 150, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.
}
}

void setup()
{
  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)

  pinMode (encoderCLK,INPUT_PULLUP);
  pinMode (encoderDT,INPUT_PULLUP);
  prvsCLK = digitalRead(encoderCLK);
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.print("Attempting to connect to SSID: ");
  Serial.print(ssid);
  WiFi.hostname(HOSTNAME);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("connected!");

  Serial.print("Setting time using SNTP");
  configTime(1 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  now = time(nullptr);
  while (now < 1510592825) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("done!");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));

  #ifdef CHECK_CA_ROOT
    BearSSL::X509List cert(digicert);
    net.setTrustAnchors(&cert);
  #endif
  #ifdef CHECK_PUB_KEY
    BearSSL::PublicKey key(pubkey);
    net.setKnownKey(&key);
  #endif
  #ifdef CHECK_FINGERPRINT
    net.setFingerprint(fp);
  #endif
  #if (!defined(CHECK_PUB_KEY) and !defined(CHECK_CA_ROOT) and !defined(CHECK_FINGERPRINT))
    net.setInsecure();
  #endif

      
  client.setServer(MQTT_HOST, MQTT_PORT);
  client.setCallback(receivedCallback);
  mqtt_connect();
       pixels.setPixelColor(0, pixels.Color(0, 0, 0));
      pixels.show();   // Send the updated pixel colors to the hardware.

}

void loop()
{
   crntCLK = digitalRead(encoderCLK);

 if (crntCLK != prvsCLK){
      // If the encoderDT state is different than the encoderCLK state then the rotary encoder is rotating counterclockwise
        if (digitalRead(encoderDT) != crntCLK) {
          servoAngle ++;

        }
        else {
          servoAngle --;
         }
         Serial.println(servoAngle);
          String myString = String(servoAngle);
          myString.toCharArray(ang, myString.length() + 1);
          client.publish(MQTT_PUB_TOPIC_angle, ang, false);
 }
  prvsCLK = crntCLK;

  now = time(nullptr);
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("Checking wifi");
    while (WiFi.waitForConnectResult() != WL_CONNECTED)
    {
      WiFi.begin(ssid, pass);
      Serial.print(".");
      delay(10);
    }
    Serial.println("connected");
  }
  else
  {
    if (!client.connected())
    {
      mqtt_connect();
    }
    else
    {
      client.loop();
    }
  }

  if (millis() - lastMillis > 5000) {
    lastMillis = millis();
    client.publish(MQTT_PUB_TOPIC, ctime(&now), false);
  }
}