hello world for esp32-wrover

This post is based mostly on Installing ESP32 Board in Arduino IDE 2 (Windows, Mac OS X, Linux) | Random Nerd Tutorials it is a good resource to get started on verify the ESP32-WROVER is working.

The hardest part is to determine what are the connector chip and installing libraries into Arduino IDE. Refer to the shared link in the beginning of this post.

Code from DeepSeek for a complicated hello world, assuming to make the LED blinks in morse code:

#include <Arduino.h>

#define LED_PIN 2  // Built-in LED on GPIO 2

// Morse code representations for A-Z
const char* morseCodes[] = {
  ".-",    // A
  "-...",  // B
  "-.-.",  // C
  "-..",   // D
  ".",     // E
  "..-.",  // F
  "--.",   // G
  "....",  // H
  "..",    // I
  ".---",  // J
  "-.-",   // K
  ".-..",  // L
  "--",    // M
  "-.",    // N
  "---",   // O
  ".--.",  // P
  "--.-",  // Q
  ".-.",   // R
  "...",   // S
  "-",     // T
  "..-",   // U
  "...-",  // V
  ".--",   // W
  "-..-",  // X
  "-.--",  // Y
  "--.."   // Z
};

void setup() {
  pinMode(LED_PIN, OUTPUT);  // Set the LED pin as an output
  Serial.begin(115200);
}

void loop() {
  String message = "SOS";  // Message to transmit in Morse code
  message.toUpperCase();   // Convert message to uppercase

  // Transmit the message in Morse code
  for (int i = 0; i < message.length(); i++) {
    char currentChar = message[i];
    if (currentChar >= 'A' && currentChar <= 'Z') {
      transmitMorse(morseCodes[currentChar - 'A']);  // Transmit Morse code for the character
    } else if (currentChar == ' ') {
      delay(1400);  // Gap between words (7 units)
    }
    delay(600);  // Gap between letters (3 units)
  }

  delay(2000);  // Wait before repeating the message
}

// Function to transmit a Morse code pattern
void transmitMorse(const char* morseCode) {
  for (int i = 0; i < strlen(morseCode); i++) {
    if (morseCode[i] == '.') {
      blinkDot();  // Transmit a dot
    } else if (morseCode[i] == '-') {
      blinkDash();  // Transmit a dash
    }
    delay(200);  // Gap between dots/dashes (1 unit)
  }
}

// Function to blink a dot (short flash)
void blinkDot() {
  digitalWrite(LED_PIN, HIGH);  // Turn the LED on
  delay(200);                   // Dot duration (1 unit)
  digitalWrite(LED_PIN, LOW);   // Turn the LED off
}

// Function to blink a dash (long flash)
void blinkDash() {
  digitalWrite(LED_PIN, HIGH);  // Turn the LED on
  delay(600);                   // Dash duration (3 units)
  digitalWrite(LED_PIN, LOW);   // Turn the LED off
}

Code to connect to WiFi:

#include <WiFi.h>

// Replace with your network credentials
const char* ssid = "myhome4iot";
const char* password = "i have the longest wifi password ever";

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

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  Serial.println("Connecting to Wi-Fi...");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  // Connection successful
  Serial.println("\nWi-Fi connected!");

  // Get and print network information
  IPAddress ip = WiFi.localIP();
  IPAddress gateway = WiFi.gatewayIP();
  IPAddress dns = WiFi.dnsIP();

  Serial.println("Network Information:");
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.print("Gateway: ");
  Serial.println(gateway);
  Serial.print("DNS Server: ");
  Serial.println(dns);
}

void loop() {
  // Nothing to do here
}
Returning IP information of ESP32

Code to scan WiFi:

#include <WiFi.h>

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

  // Set ESP32 to station mode
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();  // Disconnect from any previous connection
  delay(100);

  Serial.println("Starting Wi-Fi scan...");
}

void loop() {
  // Scan for nearby Wi-Fi networks
  int numNetworks = WiFi.scanNetworks();

  if (numNetworks == 0) {
    Serial.println("No networks found.");
  } else {
    Serial.print(numNetworks);
    Serial.println(" networks found:");
    for (int i = 0; i < numNetworks; i++) {
      // Print SSID and RSSI for each network
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));  // SSID
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));  // Signal strength (RSSI)
      Serial.print(" dBm)");
      Serial.print(" [");
      Serial.print(getEncryptionType(WiFi.encryptionType(i)));  // Encryption type
      Serial.println("]");
    }
  }

  Serial.println("-----------------------------");
  delay(10000);  // Wait 10 seconds before scanning again
}

// Function to convert encryption type to a human-readable string
String getEncryptionType(wifi_auth_mode_t encryptionType) {
  switch (encryptionType) {
    case WIFI_AUTH_OPEN:
      return "Open";
    case WIFI_AUTH_WEP:
      return "WEP";
    case WIFI_AUTH_WPA_PSK:
      return "WPA";
    case WIFI_AUTH_WPA2_PSK:
      return "WPA2";
    case WIFI_AUTH_WPA_WPA2_PSK:
      return "WPA/WPA2";
    case WIFI_AUTH_WPA2_ENTERPRISE:
      return "WPA2 Enterprise";
    case WIFI_AUTH_WPA3_PSK:
      return "WPA3";
    case WIFI_AUTH_WPA2_WPA3_PSK:
      return "WPA2/WPA3";
    default:
      return "Unknown";
  }
}

Unfortunately, due to the ESP32-WROVER hardware limitation, any modern 5GHz WiFi will not be able to be scanned or detected. On top of that, the stock ESP32-WROVER-IE needs to have a actual wifi cable to extend its range.

WiFi range is too short to scan a large area as well as limitation of WiFi hardware/chip

Adding Amazon Web Service EC2 instances IP and names into PuTTY session automagically

Introduction :

The motivation of creation of this script were due to non-persistent and ever changing state of Amazon Web Service(AWS) that causes my infrastructure changes more frequently. It will be labor intensive to create, update and remove session manually in PuTTY to reflect the changes in the AWS.

The pre-requisite :

The idea :

Using a batch scripting to warp and call the powershell. Then the powershell script will call the installed EC2 API tools provided by Amazon.

 

Then, powershell is too used to do the parsing of text returned by the EC2 API tools. In all the complexity of powershell will generate a new registry file for windows.

 

Finally, the batch script will call registry editor that would import the exported EC2 instance values into the PuTTY session repository.

 

In implementing the script, I have created 4 files, the batch script generate_putty_session.bat, the poweshell script generate_putty_session.ps1 , the registry file header reg_header.txt and lastly, the reg_putty.txt contains the text of default PuTTY configuration in a form of windows registry format.

 

Codes of generate_putty_session.bat :


@echo off
powershell -version 2.0 -ExecutionPolicy unrestricted %~dp0generate_putty_sessions.ps1
regedit.exe /s %userprofile%\putty_list.reg

 

Codes of generate_putty_session.ps1 :

 


#Preloading scripts
#Removing old reg file
if ( Test-Path $env:userprofile\putty_list.reg){
  del $env:userprofile\putty_list.reg
}

#Check environment for Windows x86 or x86_64
if ([IntPtr]::Size -eq 4){
  if ( Test-Path "C:\Program Files\AWS Tools\PowerShell\AWSPowerShell"){
    import-module "C:\Program Files\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1"
  }
  else{
    write-host "AWS Tools for PowerShell was not install, exiting. Download at http://aws.amazon.com/powershell/"
    exit
  }
}
else{
  if ( Test-Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell"){
    import-module "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1"
  }
  else{
    write-host "AWS Tools for PowerShell was not install, exiting. Download at http://aws.amazon.com/powershell/"
    exit
  }
}

#Check env variable for required EC2 configuration
if (-not (Test-Path Env:\EC2_HOME)){
  write-host "Environment variable EC2_HOME was not found, please ensure your EC2 API Tools were properly installed or configured or setup."
  exit
}

if (-not (Test-Path Env:\EC2_CERT)){
  write-host "Environment variable EC2_CERT was not found, please ensure your EC2 API Tools were properly installed or configured or setup."
  exit
}

if (-not (Test-Path Env:\EC2_PRIVATE_KEY)){
  write-host "Environment variable EC2_PRIVATE_KEY was not found, please ensure your EC2 API Tools were properly installed or configured or setup."
  exit
}

#Get my script path
$myPath = split-path -parent $MyInvocation.MyCommand.Definition

if(-not (Test-Path -path $myPath\reg_header.txt)){
  write-host "Please make sure reg_header.txt is in " $myPath
  exit
}

if(-not (Test-Path -path $myPath\reg_putty.txt)){
  write-host "Please make sure reg_header.txt is in " $myPath
  exit
}

Copy-Item $myPath\reg_header.txt $env:userprofile
Copy-Item $myPath\reg_putty.txt $env:userprofile

#Main body and function of the script.
#Creating file to link instance ID with Public DNS
ec2-describe-instances --filter `"virtualization-type=paravirtual`" --filter `"instance-state-name=running`" --filter `"tag:Name=/*/*`" | Select-String -pattern INSTANCE -caseSensitive | foreach { "$($_.ToString().split()[1,3])" >> $env:userprofile\awsinstanceIP.tmp}

#Creating a file to link instance ID with Name tag
ec2-describe-instances --filter `"virtualization-type=paravirtual`" --filter `"instance-state-name=running`" --filter `"tag:Name=/*/*`" | Select-String -pattern Name -caseSensitive | foreach { "$($_.ToString().split()[2,4])" >> $env:userprofile\awsinstanceName.tmp}

# Clean up results, removing RenderWorkerGroup
Get-Content $env:userprofile\awsinstanceName.tmp | Select-String -pattern RenderWorkerGroup -NotMatch | foreach { "$($_.ToString().split()[0,1])" >> $env:userprofile\awsinstanceNameClean.tmp}

#$awsInstanceIDIP = Get-Content $env:userprofile\awsinstanceIP.tmp
$awsInstanceCleanName =  Get-Content $env:userprofile\awsinstanceNameClean.tmp
$count = 0

# Create HashTable from File.
ForEach ($line in $awsInstanceCleanName) {
  if ($count -le 0 ) {
    $myHash = @{ $line.ToString().Split()[0] = $line.ToString().Split()[1]}
  }
  else{
    $myHash.Set_Item($line.ToString().Split()[0], $line.ToString().Split()[1])
  }
  $count = $count + 1
}
$count = 0

Get-Content $env:userprofile\awsinstanceIP.tmp | ForEach-Object {

  $line = $_
  $myHash.GetEnumerator() | ForEach-Object {
    if ($line -match $_.Key)
    {
      if ($_.value.ToString().Contains("render-worker")){
        $replacement = $_.Key.ToString() + " " + $_.Value.ToString() + "/" + $_.Key.ToString()
      }
      else{
        $replacement = $_.Key.ToString() + " " + $_.Value.ToString()
      }
      $line = $line -replace $_.Key, $replacement
    }
  }
  $line
} | Set-Content -Path $env:userprofile\awsinstanceResult.tmp

del $env:userprofile\awsinstanceIP.tmp
del $env:userprofile\awsinstanceName.tmp
del $env:userprofile\awsinstanceNameClean.tmp

$awsinstanceResult = Get-Content $env:userprofile\awsinstanceResult.tmp

#Adding header into file content.
Add-Content $env:userprofile\awsinstanceReg_List.tmp $(Get-Content $env:userprofile\reg_header.txt)
Add-Content $env:userprofile\awsinstanceReg_List.tmp "`r"

# Populating body of the file before converting into registry file.
foreach ($line in $awsinstanceResult){
  $reg_line = "`[HKEY_CURRENT_USER\Software\Simontatham\PuTTY\Sessions\" + $line.ToString().Split()[1] + "]"
  Add-Content $env:userprofile\awsinstanceReg_List.tmp $reg_line
  $reg_line = "`"HostName`"=`"" + $line.ToString().Split()[2] + "`""
  Add-Content $env:userprofile\awsinstanceReg_List.tmp $reg_line
  # Add fillers to the sessions
  Add-Content $env:userprofile\awsinstanceReg_List.tmp $(Get-Content $env:userprofile\reg_putty.txt)
  Add-Content $env:userprofile\awsinstanceReg_List.tmp "`r"
}

Get-Content $env:userprofile\awsinstanceReg_List.tmp | Add-Content $env:userprofile\putty_list.reg

#Removing all temporary files
del $env:userprofile\awsinstanceReg_List.tmp
del $env:userprofile\awsinstanceResult.tmp
del $env:userprofile\reg_header.txt 
del $env:userprofile\reg_putty.txt
Before running the script, pay special attention to the powershell code of generate_putty_sessions.ps1 at line 61, 64, 67 and 91. Make needed change to the format of your AWS Tag “Name”.

 

The filter in line 61, 64 would create 2 different files using the same ec2 api tools command. It is working under assumption that you have named your AWS instances using format as such /[product_name]/[environment]/[sub-system]/[server-number] .

 

Line 67 would use the similar pattern that I have used in my environment to remove unwanted servers from being added into the PuTTY sessions. In my code I am removing output that contains RenderWorkerGroup.

 

Line 91, just enforcing the format name for instances which is generated by AutoScaling /[product_name]/[environment]/[sub-system]/[aws-instance-id]

 
 

Using the script :

Place all the files into a single folder in your Windows machine.

 

Run the generate_putty_sessions.bat in the Administrator command prompt. In less than 2 minutes

 

Your PuTTY should contains all the session imported from Amazon Web Service EC2.

 
 

Code Download :

putty_session_generator

Cloudkick customed plugins for windows

Cloudkick which is part of RackSpace provides Agent based monitoring for external servers and cloud servers. Other than monitoring computer resources such as CPU, memory, HDD utilization. It is able to cater for customed check which is known as customed plugin. In other words, Cloudkick offers limitless way of administrator to monitor their IT assets as host level which is limited to the operating systems shell scripting support as well as limited to the creativity of the scripters.

Continue reading

Automating ossec installation in linux

One of the challenges that I have faced in linux environment were to automate installation.

Of course it is simple to script using bash in linux to run rpm or deb binary installation.

What if the installation comes with an interactive installation or installer which is coded as a bash script. Yes, I am looking at you OSSEC .

Continue reading