• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer
  • Home
  • Create a VM ($25 Credit)
  • Buy a Domain
  • 1 Month free Back Blaze Backup
  • Other Deals
    • Domain Email
    • Nixstats Server Monitoring
    • ewww.io Auto WordPress Image Resizing and Acceleration
  • About
  • Links

IoT, Code, Security, Server Stuff etc

Views are my own and not my employer's.

Personal Development Blog...

Coding for fun since 1996, Learn by doing and sharing.

Buy a domain name, then create your own server (get $25 free credit)

View all of my posts.

  • Cloud
    • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
    • How to buy a new domain and SSL cert from NameCheap, a Server from Digital Ocean and configure it.
    • Setting up a Vultr VM and configuring it
    • All Cloud Articles
  • Dev
    • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
    • How to setup pooled MySQL connections in Node JS that don’t disconnect
    • NodeJS code to handle App logins via API (using MySQL connection pools (1000 connections) and query parameters)
    • Infographic: So you have an idea for an app
    • All Development Articles
  • MySQL
    • Using the free Adminer GUI for MySQL on your website
    • All MySQL Articles
  • Perf
    • PHP 7 code to send object oriented sanitised input data via bound parameters to a MYSQL database
    • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
    • Measuring VM performance (CPU, Disk, Latency, Concurrent Users etc) on Ubuntu and comparing Vultr, Digital Ocean and UpCloud – Part 1 of 4
    • Speeding up WordPress with the ewww.io ExactDN CDN and Image Compression Plugin
    • Setting up a website to use Cloudflare on a VM hosted on Vultr and Namecheap
    • All Performance Articles
  • Sec
    • Using the Qualys FreeScan Scanner to test your website for online vulnerabilities
    • Using OWASP ZAP GUI to scan your Applications for security issues
    • Setting up the Debian Kali Linux distro to perform penetration testing of your systems
    • Enabling TLS 1.3 SSL on a NGINX Website (Ubuntu 16.04 server) that is using Cloudflare
    • PHP implementation to check a password exposure level with Troy Hunt’s pwnedpasswords API
    • Setting strong SSL cryptographic protocols and ciphers on Ubuntu and NGINX
    • Securing Google G Suite email by setting up SPF, DKIM and DMARC with Cloudflare
    • All Security Articles
  • Server
    • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
    • All Server Articles
  • Ubuntu
    • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
    • Useful Linux Terminal Commands
    • All Ubuntu Articles
  • VM
    • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
    • All VM Articles
  • WordPress
    • Speeding up WordPress with the ewww.io ExactDN CDN and Image Compression Plugin
    • Installing and managing WordPress with WP-CLI from the command line on Ubuntu
    • How to backup WordPress on a host that has CPanel
    • Moving WordPress to a new self managed server away from CPanel
    • Moving a CPanel domain with email to a self managed VPS and Gmail
    • All WordPress Articles
  • All

Code

HomePi – Raspberry PI powered touch screen showing information from house-wide sensors

March 14, 2022 by Simon

This post is a work in progress (14/3/2022, v0.9.63 – PCB’s v0.2 Designed and Ordered

Summary

After watching this video from Jeff Geerling (demonstrating how to build a Air Quality Sensor) I have decided to make 2. but why not build something bigger?

I want to make a RaspBerry Pi server with a touch screen to receive data from a dozen other WeMos Sensors that I will build.

The Plan

Below is a rough plan of what I am building

In a nutshell, it will be 20x WeMos Sensors recording

Picture of20x WeMoss Sensors, weather station and co2 sensors talking to an api that saves to MySQL then mysql being ready buy a webpage and touch screen panel

I ordered all the parts from Amazon, BangGood, AliExpress, eBay, Core Electronics and Kogan.

Fresh Bullseye Install (Buster upgrade failed)

On 21/11/2021 I tried to manually update Buster to Bullseye (without taking a backup first (bad idea)). I followed this guide to reinstall Rasbian from scratch (this with Bullseye)

Storage Type

Before I begin I need to decide on what storage media to use on the Raspberry Pi. I hate how unreliable and slow MicroSD cards. I tried using an old 128GB SATA SSD, a 1TB Magnetic Hard Drive, a SATA M.2 SSD and NVME M.2 in a USB caddy.

I decided to use a spare 250GB SATA based M.2 Solid State from my son’s PC in Geekworm X862 SATA M.21 Expansion board.

With this board I can bolt the M.2 Solid State Drive into a expansion board under the pi and Power it from the RaspBerry Pi USB Port.

Nice and tidy

I zip-tied a fan to the side of the boards to add a little extra airflow over the solid state drive

32Bit, 64Bit, Linux or Windows

Before I begin I set up Raspbian on an empty Micro SD card (just to boot it up and flash the firmware to the latest version). This is very easy and documented elsewhere. I needed the latest firmware to ensure boort from USB Drive (not Micro SD card was working).

I ran rpi-update and flashed the latest firmware onto my Raspberry Pi. Good, write up here.

When my Raspberry Pi had the latest firmware I used the Raspberry Pi Imager to install the 32 Bit Raspberry Pi OS.

I do have a 8GB Raspberry Pi 4 B, 64Bit Operating Systems do exist but I stuck with 32 bit for compatibility.

Ubuntu 64bit for Raspberry Pi Links

  • Install Ubuntu on a Raspberry Pi | Ubuntu
    • Server Setup Links
      • How to install Ubuntu Server on your Raspberry Pi | Ubuntu
    • Desktop Setup Links
      • How to install Ubuntu Desktop on Raspberry Pi 4 | Ubuntu

Windows 10 for Raspberry Pi Links
https://docs.microsoft.com/en-us/windows/iot-core/tutorials/quickstarter/prototypeboards
https://docs.microsoft.com/en-us/answers/questions/492917/how-to-install-windows-10-iot-core-on-raspberry-pi.html
https://docs.microsoft.com/en-us/windows/iot/iot-enterprise/getting_started

Windows 11 for Raspberry Pi Links
https://www.youtube.com/user/leepspvideo
https://www.youtube.com/watch?v=WqFr56oohCE
https://www.worproject.ml

Setting up the Raspberry Pi Server

These are the steps I used to setup my Pi

Dedicated IP

Before I began I ran ifconfig on my Pi to obtain my Raspberry Pi’s wireless cards mac address. I logged into my Router and setup a dedicated IP (192.168.0.50), this way I can have a IP address thta remains the same.

Hostname

I set my hostname here

sudo nano /etc/hosts
sudo nano /etc/hostname

I verified my hostname with this command

hostname

I verified my IP address with this command

hostname -I

Samba Share

I setup the Samba service to allow me to copy files to and from the Pi

sudo apt-get install samba samba-common-bin
sudo apt-get update

I made a folder to share files

 mkdir ~/share

I edited the Samba config file

sudo nano /etc/samba/smb.conf

In the config file I set my workgroup settings


workgroup = Hyrule
wins support = yes

I defined a share at the bottom of the config file (and saved)

[PiShare]
comment=Raspberry Pi Share
path=/home/pi/share
browseable=Yes
writeable=Yes
only guest=no
create mask=0777
directory mask=0777
public=no

I set a smb password

sudo smbpasswd -a pi
New SMB password: ********
Retype new SMB password: ********

I tested the share froma Windows PC

And the share is accessible on the Raspberry Pi

Great, now I can share files with drag and drop (instead of via SCP)

Mono

I know how to code C# Windows Executables, I have 25 years experince. I do nt want to learn Java or Python to code a GUI application for a touch screen if possible.

I setup Mono from Home | Mono (mono-project.com) to be anbe to run Windows C# EXE’s on Rasbian

sudo apt install apt-transport-https dirmngr gnupg ca-certificates

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF

echo "deb https://download.mono-project.com/repo/debian stable-raspbianbuster main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list

sudo apt update

sudo apt install mono-devel

I copied an EXE I wrote in C# on Windows and ran it with Mono

sudo mono ~/HelloWorld.exe
Exe Test OK

This worked.

Nginx Web Server

I Installed NginX and configured it

sudo apt-get install nginx

I created a /www folder for nginx

sudo mkdir /www

I created a place-holder file in the www root

sudo nano /wwww/index.html

I set permissions to allow Nginx to access /www

sudo chown -R www-data:www-data /www

I edited the NginX config as required

sudo nano /etc/nginx/sites-enabled/default
sudo nano /etc/nginx/nginx.conf 

I tested and reloaded the nginx config


sudo nginx -t
sudo nginx -s reload
sudo systemctl start nginx

I started NginX

sudo systemctl start nginx

I tested nginx in a web browser

NodeJS/NPM

I installed NodeJS

sudo apt update
sudo apt install nodejs npm -y

I verified Node was installed

nodejs --version
> v12.22.5

PHP

I installed PHP

sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg

echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list

sudo apt update

sudo apt install -y php8.0-common php8.0-cli php8.0-xml

I verified PHP with this command

php --version

> PHP 8.0.13 (cli) (built: Nov 19 2021 06:40:53) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.13, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.13, Copyright (c), by Zend Technologies

I installed PHP-FPM

sudo apt-get install php8.0-fpm

I verified the PHP FPM sock was available before adding it to the NGINX Config

sudo ls /var/run/php*/**.sock
> /var/run/php/php8.0-fpm.sock  /var/run/php/php-fpm.sock

I reviewed PHP Settings

sudo nano /etc/php/8.0/cli/php.ini 
sudo nano /etc/php/8.0/fpm/php.ini

I created a /www/ppp.php file with this contents

<?php
  phpinfo(); // all info
  // module info, phpinfo(8) identical
  phpinfo(INFO_MODULES);
?>

PHP is working

PHP Test OK

I changed these php.ini settings (fine for local development).

max_input_vars = 1000
memory_limit = 1024M
max_file_uploads = 20M
post_max_size = 20M
display_errors = on

MySQL Database

I installed MariaDB

sudo apt install mariadb-server

I updated my pi password

passwd

I ran the Secure MariaDB Program

sudo mysql_secure_installation

After setting each setting I want to run mysql as root to test mysql

PHPMyAdmin

I installed phpmyadmin to be able to edit mysql databases via the web

I followed this guide to setup phpmyadmin via lighthttp and then via nginx

I then logged into MySQL, set user permissions, create a test database and changes settings as required.

NginX to NodeJS API Proxy

I edited my NginX config to create a NodeAPI Proxy

Test Webpage/API

Todo

I installed PM2 the NodeJS agent software

sudo npm install -g pm2 

Node apps can be started as a service from cli

pm2 start api_v1.js

PM2 status

pm2 status

You can delete node apps from PM2 (if desired)

pm2 delete api_v1.js

Sending Email from CLI

I setup send email to allow emails to be sent from the cli with these commands

 sudo apt-get install libio-socket-ssl-perl libnet-ssleay-perl sendemail  

I logged into my GSuite account and setup an alias and app password to use.

Now I can send emails from the CLI

sudo sendemail -f [email protected] -t [email protected] -u "Test Email From PiHome" -m "Test Email From PiHome" -s smtp.gmail.com:587 -o tls=yes -xu [email protected] -xp **************

I added this to a Bash script (“/Scripts/Up.sh”) and added an event to send an email every 6 hours

7 Inch Full View LCD IPS Touch Screen 1024*600 

I purchased a 7″ Touch screen from Banggood. I got a head up from the following Video.

I plugged in the touch USB cable to my Pi’s USB3 port. I pliugged the HDMI adapter into the screen and the pi (with the supplied mini plug).

I turned on the pi and it work’s and looks amazing.

This is displaying a demo C# app I wrote. It’s running via mono.

I did have to add the following to config.txt to bet native resolution. The manual on the supplied CD was helpful (but I did not check it at first).

max_usb_current=1
hdmi_force_hotplug=1
config_hdmi_boost=7
hdmi_group=2
hdmi_mode=1
hdmi_mode=87 
hdmi_drive=1
display_rotate=0
hdmi_cvt 1024 600 60 6 0 0 0
framebuffer_width=1024
framebuffer_height=600

PiJuice UPS HAT

I purchased an external LiPi UPS to keep the raspberry pi fed with power (even when the power goes out)

The stock battery was not charged and was quite weak when I first installed it. Do fully charge the battery before testing.

PiJuice

Stock Battery = 3.7V @ 1820mAh

Stock Battery = 3.7V @ 1820mAh

Below are screenshots so the PIJuice Setup.

PiJuice HAT Settings

PiJuice General Settings

General Settings

There is an option to set events for every button

Extensive screen to set button events

LED Status color and function

Set LED status and color

IO for the PiJuice Input. I will sort this out later.

PiJuice IO settings

A new firmware was available. I had v1.4

Update firmware screen

I updated the firmware

Firmware update worked

Firmware flash success

Battery settings

Battery Settings

PiJuice Button Config

Button config

Wake Up Alarm time and RTC

Clock Settings

System Settings

System Settings

System Events

system settings page

User Scripts

Define user scripts

I ordered a bigger battery as my Screen, M.2, Fan and UPS consume near the maximum of the stock battery.

10,000mAh battery

After talking with the seller of the battery they advised I setup the 10,000mAh battery using the 1,000mAh battery setup in PiJuice but change the Capacity and Charge Current

  • Capacity = 10000C
  •  cutoff voltage

And for battery longevity set the 

  • Cutoff voltage: 3,250mv

Final Battery Setup

Battery settings based off 1000mAh battery profile , Capacity 10,000 mAh, Charge current 850 and Cutoff 3250mV

WeMos Setup

I orderd 20x Wemos Mini D1 Pro (16Mbit) clones to use to run the sensors. I soldered the legs on in batches of 8

WeMos installed on breadboards ready to solder pins

Soldering was not perfect but worked

20x soldered wemos

Soldering is not perfect but each joint was triple tested.

Close up of soldered joints

I only had one dead WeMos.

I will set up the final units on ProtoBoards.

Protoboard

20x Wemos ready for service and the external aerial is glued down. The hot glue was a bad idea, I had to rotate a resistor under the hot glue.

20x wemos ready.

Revision

I ended up reordering the WeMos Mini’s and soldering on Female headers so I can add OLED screens

air mon enclosure

I added female headers to allow an OLED screen

new wemos

I purchased a microscope tpo be able to see better.

microscope

Each sensor will have a mini OLED screen.

mini oled screen

0.66″ OLED Screens

oled screen

I designed a PCB in Photoshop and had it turned into a PCB via https://www.fiverr.com/syedzamin12. I ordered 30x bloards from https://jlcpcb.com/

Custom PCB

The PCB’s fit inside the new enclosure perfectly

I am waiting for smaller screws to arrive.

PCB v0.2

I decided to design a board with 2 switches (and a light sensor to turn the screen off at night)

Breadboard Prototype

Prototype

I spoke to https://www.fiverr.com/syedzamin12 and withing 24 hours a PCB was designed

I Layers

This time I will get a purple PCB from JLCPCB and add a dinosaur for my son

Top PCB View

TOP PCB View

Back PCB View

Back PCB View

3D PC View

3D PCB view

JLCPCB made the board in 3 days

3 days

Now I need to wait a few weeks for the new PCB to arrive

Also, I finsihed the firmware for v0.2 PCB

I ordered some switches

I also ordered some reset buttons

I might add a larger 0.96″ OLED screen

Wifi and Static IP Test

I uploaded a skepch to each WeMos and tested the Wifi and Static IP thta was given.

Sketch

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>


#define SERVER_IP "192.168.0.50"

#ifndef STASSID
#define STASSID "wifi_ssid_name"
#define STAPSK  "************"
#endif

void setup() {

  Serial.begin(115200);

  Serial.println();
  Serial.println();
  Serial.println();

  WiFi.begin(STASSID, STAPSK);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());

}

void loop() {
  // wait for WiFi connection
  if ((WiFi.status() == WL_CONNECTED)) {

    WiFiClient client;
    HTTPClient http;

    Serial.print("[HTTP] begin...\n");
    // configure traged server and url
    http.begin(client, "http://" SERVER_IP "/api/v1/test"); //HTTP
    http.addHeader("Content-Type", "application/json");

    Serial.print("[HTTP] POST...\n");
    // start connection and send HTTP header and body
    int httpCode = http.POST("{\"hello\":\"world\"}");

    // httpCode will be negative on error
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      Serial.printf("[HTTP] POST... code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK) {
        const String& payload = http.getString();
        Serial.println("received payload:\n<<");
        Serial.println(payload);
        Serial.println(">>");
      }
    } else {
      Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    http.end();
  }

  delay(1000);
}

The Wemos booted, connected to WiFi, set and IP, and tried to post a request to a URL.

........................................................
Connected! IP address: 192.168.0.51
[HTTP] begin...
[HTTP] POST...
[HTTP] POST... failed, error: connection failed

The POST failed because my PI API Server was off.

Touch Screen Enclosure

I constructed a basic enclosure and screwed the touch screen to it. I need to find  aflexible black scrip to put around the screen and cover up the gaps.

Wooden box with the screen in it

The touch screen has been screwed in.

Screen screwed in

Over the Air Updating

I followed this guide and having the WeMos updatable over WiFi.

Basically, I installed the libraries “AsyncHTTPSRequest_Generic”, “AsyncElegantOTA”, “AsyncHTTPRequest_Generic”, “ESPAsyncTCP” and “ESPAsyncWebServer”.

Manage Libraries

A few libraries would not download so I manually downloaded the code from the GitHub repository from Confirm your account recovery settings (github.com) and then extracted them to my Documents\Arduino\libraries folder.

I then opened the exampel project “AsyncElegantOTA\ESP8266_Async_Demo”

I reviewed the code

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

const char* ssid = "........";
const char* password = "........";

AsyncWebServer server(80);


void setup(void) {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hi! I am ESP8266.");
  });

  AsyncElegantOTA.begin(&server);    // Start ElegantOTA
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  AsyncElegantOTA.loop();
}
I added my Wifi SSID and password, saved the project and compiled a the code and wrote it to my WeMos Mini D1

I added LED Blink Code

void setup(void) {
  ...
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
  ...
}
void loop(void) {
 ...
  delay(1000);                      // Wait for a second
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
  delay(1000);                      // Wait for two seconds (to demonstrate the active low LED)
 ...
}

I compiled and tested the code

Now to get new code changes to the WeMos Mini via a binary, I edited the code (chnaged the LED blink speed) and clicked “Export Compiled Binary”

Compole Binary

When the binary compiled I opened the Sketch Folder

Show Sketch folder

I could see a bin file.

Bin File

I loaded the http://192.168.0.51/update and selected the bin file.

The new firmwaere applied.

Flashing

I navighated back to http://192.168.0.51

TIP: Ensure you add the starter sketch that has your wifi details in there.

Password Protection

I changed the code to add a basic passeord on access ad on OTA update

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>


//Saved Wifi Credentials (Research Encruption Later or store in FRAM Module?
const char* ssid = "your-wifi-ssid";
const char* password = "********";

//Credentials for the regular user to access "http://{ip}:{port}/"
const char* http_username = "user";
const char* http_password = "********";

//Credentials for the admin user to access "http://{ip}:{port}/update/"
const char* http_username_admin = "admin";
const char* http_password_admin = "********";

//Define the Web Server Object
AsyncWebServer server(80);

void setup(void) {
  Serial.begin(115200);       //Serial Mode (Debug)
    
  WiFi.mode(WIFI_STA);        //Client Mode
  WiFi.begin(ssid, password); //Connect to Wifi
 
  Serial.println("");

  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // HTTP basic authentication on the root webpage
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    if(!request->authenticate(http_username, http_password))
        return request->requestAuthentication();
    request->send(200, "text/plain", "Login Success! ESP8266 #001.");
  });

  //This is the OTA Login
  AsyncElegantOTA.begin(&server, http_username_admin, http_password_admin);

  
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  AsyncElegantOTA.loop();

  digitalWrite(LED_BUILTIN, LOW);
  delay(8000);                      // Wait for a second
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
  delay(8000);                      // Wait for two seconds (to demonstrate the active low LED)

}

Password prompt for users accessing the device.

Login scree

Password prompt for admin users accessing the device.

admin password protect

Later I will research encrypting the password and storing it on SPIFFS partition or a FRAM memory module.

Adding the DHT22 Sensors

I received my paxckl of DHT22 Sensors (AMT2302).

Specifications

  • Operating Voltage: 3.5V to 5.5V
  • Operating current: 0.3mA (measuring) 60uA (standby)
  • Output: Serial data
  • Temperature Range: 0°C to 50°C
  • Humidity Range: 20% to 90%
  • Resolution: Temperature and Humidity both are 16-bit
  • Accuracy: ±1°C and ±1%

I wired it up based on this Adafruit post.

DHT22 Wired Up on a breadboard.

DHT22 and Basic API Working

I will not bore you with hours or coding and debugging so here is my code thta

  • Allows the WeMos D1 Mini Prpo (ESP8266) to connect to WiFi
  • Web Server (with stats)
  • Admin page for OTA updates
  • Password Prpotects the main web folder and OTA admin page
  • Reading DHT Sensor values
  • Debug to serial Toggle
  • LED activity Toggle
  • Json Serialization
  • POST DHT22 data to an API on the Raspberry PI
  • Placeholder for API return values
  • Automatically posts data to the API ever 10 seconds
  • etc

Here is the work in progress ESP8288 Code

#include <ESP8266WiFi.h>        // https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFi.h
#include <ESPAsyncTCP.h>        // https://github.com/me-no-dev/ESPAsyncTCP
#include <ESPAsyncWebServer.h>  // https://github.com/me-no-dev/ESPAsyncWebServer
#include <AsyncElegantOTA.h>    // https://github.com/ayushsharma82/AsyncElegantOTA
#include <ArduinoJson.h>        // https://github.com/bblanchon/ArduinoJson
#include "DHT.h"                // https://github.com/adafruit/DHT-sensor-library
                                // Written by ladyada, public domain

//Todo: Add Authentication
//Fyi: https://api.gov.au/standards/national_api_standards/index.html

#include <ESP8266HTTPClient.h>  //POST Client

//Firmware Stats
bool bDEBUG = true;        //true = debug to Serial output
                           //false = no serial output
//Port Number for the Web Server
int WEB_PORT_NUMBER = 1337; 

//Post Sensor Data Delay
int POST_DATA_DELAY = 10000; 

bool bLEDS = true;         //true = Flash LED
                           //false =   NO LED's
//Device Variables
String sDeviceName = "ESP-002";
String sFirmwareVersion = "v0.1.0";
String sFirmwareDate = "27/10/2021 23:00";

String POST_SERVER_IP = "192.168.0.50";
String POST_SERVER_PORT = "";
String POST_ENDPOINT = "/api/v1/test";

//Saved Wifi Credentials (Research Encryption later and store in FRAM Module?
const char* ssid = "your_wifi_ssid";
const char* password = "***************";

//Credentials for the regular user to access "http://{ip}:{port}/"
const char* http_username = "user";
const char* http_password = "********";

//Credentials for the admin user to access "http://{ip}:{port}/update/"
const char* http_username_admin = "admin";
const char* http_password_admin = "********";

//Define the Web Server Object
AsyncWebServer server(WEB_PORT_NUMBER);    //Feel free to chnage the port number

//DHT22 Temp Sensor
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
#define DHTPIN 5
DHT dht(DHTPIN, DHTTYPE);

//Common Variables
String thisBoard = ARDUINO_BOARD;
String sHumidity = "";
String sTempC = "";
String sTempF = "";
String sJSON = "{ }";

//DHT Variables
float h;
float t;
float f;
float hif;
float hic;


void setup(void) {

  //Turn On PIN
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
  
  //Serial Mode (Debug)
  //Debug LED Flash
  if (bLEDS) {
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);                      // Wait for a second
    digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
    delay(100);                      // Wait for two seconds (to demonstrate the active low LED)    
  }

  if (bDEBUG) Serial.begin(115200);
  if (bDEBUG) Serial.println("Serial Begin");

  //Debug LED Flash
  if (bLEDS) {
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);                      // Wait for a second
    digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
    delay(100);                      // Wait for two seconds (to demonstrate the active low LED)    
  }
  if (bDEBUG) Serial.println("Wifi Setup");
  if (bDEBUG) Serial.println(" - Client Mode");
  
  WiFi.mode(WIFI_STA);        //Client Mode
  
  if (bDEBUG) Serial.print(" - Connecting to Wifi: " + String(ssid));
  WiFi.begin(ssid, password); //Connect to Wifi
 
  if (bDEBUG) Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    if (bDEBUG) Serial.print(".");
  }
  if (bDEBUG) Serial.println("");
  if (bDEBUG) Serial.print("- Connected to ");
  if (bDEBUG) Serial.println(ssid);
  
  if (bDEBUG) Serial.print("IP address: ");
  if (bDEBUG) Serial.println(WiFi.localIP());

  //Debug LED Flash
  if (bLEDS) {
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);                      // Wait for a second
    digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
    delay(100);                      // Wait for two seconds (to demonstrate the active low LED)    
  }

  
  // HTTP basic authentication on the root webpage
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    if(!request->authenticate(http_username, http_password))
        return request->requestAuthentication();
    
        String sendHtml = "";
        sendHtml = sendHtml + "<html>\n";
        sendHtml = sendHtml + " <head>\n";
        sendHtml = sendHtml + " <title>ESP# 002</title>\n";
        sendHtml = sendHtml + " <meta http-equiv=\"refresh\" content=\"5\";>\n";
        sendHtml = sendHtml + " </head>\n";
        sendHtml = sendHtml + " <body>\n";
        sendHtml = sendHtml + " <h1>ESP# 002</h1>\n";
        sendHtml = sendHtml + " <u2>Debug</h2>";
        sendHtml = sendHtml + " <ul>\n";
        sendHtml = sendHtml + " <li>Device Name: " + sDeviceName + " </li>\n";
        sendHtml = sendHtml + " <li>Firmware Version: " + sFirmwareVersion + " </li>\n";
        sendHtml = sendHtml + " <li>Firmware Date: " + sFirmwareDate + " </li>\n";
        sendHtml = sendHtml + " <li>Board: " + thisBoard + " </li>\n";
        sendHtml = sendHtml + " <li>Auto Refresh Root: On </li>\n";
        sendHtml = sendHtml + " <li>Web Port Number: " + String(WEB_PORT_NUMBER) +" </li>\n";
        sendHtml = sendHtml + " <li>Serial Debug: " + String(bDEBUG) +" </li>\n";
        sendHtml = sendHtml + " <li>Flash LED's Debug: " + String(bLEDS) +" </li>\n";
        sendHtml = sendHtml + " <li>SSID: " + String(ssid) +" </li>\n";
        sendHtml = sendHtml + " <li>DHT TYPE: " + String(DHTTYPE) +" </li>\n";
        sendHtml = sendHtml + " <li>DHT PIN: " + String(DHTPIN) +" </li>\n";
        sendHtml = sendHtml + " <li>POST_DATA_DELAY: " + String(POST_DATA_DELAY) +" </li>\n";

        sendHtml = sendHtml + " <li>POST_SERVER_IP: " + String(POST_SERVER_IP) +" </li>\n";
        sendHtml = sendHtml + " <li>POST_ENDPOINT: " + String(POST_ENDPOINT) +" </li>\n";
        
        sendHtml = sendHtml + " </ul>\n";
        sendHtml = sendHtml + " <u2>Sensor</h2>";
        sendHtml = sendHtml + " <ul>\n";
        sendHtml = sendHtml + " <li>Humidity: " + sHumidity + "% </li>\n";
        sendHtml = sendHtml + " <li>Temp: " + sTempC + "c, " + sTempF + "f. </li>\n";
        sendHtml = sendHtml + " <li>Heat Index: " + String(hic) + "c, " + String(hif) + "f.</li>\n";
        sendHtml = sendHtml + " </ul>\n";
        sendHtml = sendHtml + " <u2>JSON</h2>";
        
        // Allocate the JSON document Object/Memory
        // Use https://arduinojson.org/v6/assistant to compute the capacity.
        StaticJsonDocument<250> doc;
        //JSON Values     
        doc["Name"] = sDeviceName;
        doc["humidity"] = sHumidity;
        doc["tempc"] = sTempC;
        doc["tempf"] = sTempF;
        doc["heatc"] = String(hic);
        doc["heatf"] = String(hif);
        
        sJSON = "";
        serializeJson(doc, sJSON);
        
        sendHtml = sendHtml + " <ul>" + sJSON + "</ul>\n";
        
        sendHtml = sendHtml + " <u2>Seed</h2>";
        long randNumber = random(100000, 1000000);
        sendHtml = sendHtml + " <ul>\n";
        sendHtml = sendHtml + " <p>" + String(randNumber) + "</p>\n";
        sendHtml = sendHtml + " </ul>\n";
       
        sendHtml = sendHtml + " </body>\n";
        sendHtml = sendHtml + "</html>\n";
        //Send the HTML   
        request->send(200, "text/html", sendHtml);
  });

  //This is the OTA Login
  AsyncElegantOTA.begin(&server, http_username_admin, http_password_admin);
  
  server.begin();
  if (bDEBUG) Serial.println("HTTP server started");
 
  if (bDEBUG) Serial.println("Board: " + thisBoard);

  //Setup the DHT22 Object
  dht.begin();
  
}

void loop(void) {

  AsyncElegantOTA.loop();

  //Debug LED Flash
  if (bLEDS) {
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);                      // Wait for a second
    digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
    delay(100);                      // Wait for two seconds (to demonstrate the active low LED)    
  }


  //Display Temp and Humidity Data

  h = dht.readHumidity();
  t = dht.readTemperature();
  f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    if (bDEBUG) Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  
  hif = dht.computeHeatIndex(f, h);         // Compute heat index in Fahrenheit (the default)
  hic = dht.computeHeatIndex(t, h, false);  // Compute heat index in Celsius (isFahreheit = false)

  if (bDEBUG) Serial.print(F("Humidity: "));
  if (bDEBUG) Serial.print(h);
  if (bDEBUG) Serial.print(F("%  Temperature: "));
  if (bDEBUG) Serial.print(t);
  if (bDEBUG) Serial.print(F("°C "));
  if (bDEBUG) Serial.print(f);
  if (bDEBUG) Serial.print(F("°F  Heat index: "));
  if (bDEBUG) Serial.print(hic);
  if (bDEBUG) Serial.print(F("°C "));
  if (bDEBUG) Serial.print(hif);
  if (bDEBUG) Serial.println(F("°F"));

  //Save for Page Load
  sHumidity = String(h,2);
  sTempC = String(t,2);
  sTempF = String(f,2);

  //Post to Pi API
    // Allocate the JSON document Object/Memory
    // Use https://arduinojson.org/v6/assistant to compute the capacity.
    StaticJsonDocument<250> doc;
    //JSON Values     
    doc["Name"] = sDeviceName;
    doc["humidity"] = sHumidity;
    doc["tempc"] = sTempC;
    doc["tempf"] = sTempF;
    doc["heatc"] = String(hic);
    doc["heatf"] = String(hif);
    
    sJSON = "";
    serializeJson(doc, sJSON);

    //Post to API
    if (bDEBUG) Serial.println(" -> POST TO API: " + sJSON);

   //Test POST
  
    if ((WiFi.status() == WL_CONNECTED)) {
  
      WiFiClient client;
      HTTPClient http;
  
    
      if (bDEBUG) Serial.println(" -> API Endpoint: http://" + POST_SERVER_IP + POST_SERVER_PORT + POST_ENDPOINT);
      http.begin(client, "http://" + POST_SERVER_IP + POST_SERVER_PORT + POST_ENDPOINT); //HTTP


      if (bDEBUG) Serial.println(" -> addHeader: \"Content-Type\", \"application/json\"");
      http.addHeader("Content-Type", "application/json");
  
      // start connection and send HTTP header and body
      int httpCode = http.POST(sJSON);
      if (bDEBUG) Serial.print("  -> Posted JSON: " + sJSON);
  
      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled

  
        //See https://api.gov.au/standards/national_api_standards/api-response.html 
        // Response from Server
        if (bDEBUG) Serial.println("  <- Return Code: " + httpCode);
                
        //Get the Payload
        const String& payload = http.getString();
          if (bDEBUG) Serial.println("   <- Received Payload:");
          if (bDEBUG) Serial.println(payload);
          if (bDEBUG) Serial.println("   <- Payload (httpcode: 201):");
          

         //Hnadle the HTTP Code
        if (httpCode == 200) {
          if (bDEBUG) Serial.println("  <- 200: Invalid API Call/Response Code");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 201) {
          if (bDEBUG) Serial.println("  <- 201: The resource was created. The Response Location HTTP header SHOULD be returned to indicate where the newly created resource is accessible.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 202) {
          if (bDEBUG) Serial.println("  <- 202: Is used for asynchronous processing to indicate that the server has accepted the request but the result is not available yet. The Response Location HTTP header may be returned to indicate where the created resource will be accessible.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 400) {
          if (bDEBUG) Serial.println("  <- 400: The server cannot process the request (such as malformed request syntax, size too large, invalid request message framing, or deceptive request routing, invalid values in the request) For example, the API requires a numerical identifier and the client sent a text value instead, the server will return this status code.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 401) {
          if (bDEBUG) Serial.println("  <- 401: The request could not be authenticated.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 403) {
          if (bDEBUG) Serial.println("  <- 403: The request was authenticated but is not authorised to access the resource.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 404) {
          if (bDEBUG) Serial.println("  <- 404: The resource was not found.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 415) {
          if (bDEBUG) Serial.println("  <- 415: This status code indicates that the server refuses to accept the request because the content type specified in the request is not supported by the server");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 422) {
          if (bDEBUG) Serial.println("  <- 422: This status code indicates that the server received the request but it did not fulfil the requirements of the back end. An example is a mandatory field was not provided in the payload.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }
        if (httpCode == 500) {
          if (bDEBUG) Serial.println("  <- 500: An internal server error. The response body may contain error messages.");
          if (bDEBUG) Serial.println("  <- " + payload);
        }

        
      } else {
        if (bDEBUG) Serial.println("   <- Unknown Return Code (ERROR): " + httpCode);
        //if (bDEBUG) Serial.printf("    " + http.errorToString(httpCode).c_str());
        
      }

    }

    if (bDEBUG) Serial.print("\n\n");

    delay(POST_DATA_DELAY);
  }

Here is a screenshot of the Arduino IDE Serial Monitor debugging the code

Serial Monitor

Here is a screenshot of the NodeJS API on the raspberry Pi accepting the POSTed data from the ESP8266

API receiving data

Here is a sneak peek of the code accpeing the Posted Data

API COde

The final code will be open sourced.

API with 2x sensors (18x more soon)

I built 2 sensors (on Breadboards) to start hitting the API

2 sensors on a breadboard

18 more sensors are ready for action (after I get tempporary USB power sorted)

18x Sensors

PiJuice and Battery save the Day

I accidentally used my Pi for a few hours (to develop the API) and I realised the power to the PiJuice was not connected.

The PiJuice worked a treat and supplied the Pi from battery

Battery power was disconnected

I plugged in the battery after 25% was drained.

Power Restored/

Research and Setup TRIM/Defrag on the M.2 SSD

Todo: Research

Add a Buzzer to the RaspBerry Pi and Connect to Pi Juice No Power Event

Todo

Wire Up a Speaker to the PiJuice

Todo: Figure out cusrom scripts and add a Piezo Speaker to the PiJuice to alert me of issues in future.

Add buttons to the enclosure

Todo

Add email alerts from the system

I logged into Google G-Suite (my domain’s email provider) and set up an email alias for my domain “[email protected]”, I added this alias to GMail (logged in with my GSuite account.

I created an app-specific password at G-Suite to allow my poi to use a dedicated password to access my email.

I installed these packages on the Raspberry Pi

sudo apt-get install libio-socket-ssl-perl libnet-ssleay-perl sendemail    

I can run this command to send an email to my primary email

sudo sendemail -f [email protected] -t [email protected]_domain.com -u "Test Email From PiHome" -m "Test Email From PiHome" -s smtp.gmail.com:587 -o tls=yes -xu [email protected]_domain.com -xp ********************

The email arrives from the Raspberry Pi

Test Email Screenshot

PiJuice Alerts (email)

In created some python scripts and configured PiJuice to Email Me

user scripts

I assigned the scripts to Events

Added functions

Python Script (CronJob) to email the batteruy level every 6 hours

Todo

Building the Co2/PM2.5 Sensors

Todo: (Waiting for parts)

The AirGradient PCB’s have arrived

Air Gradient PCB's

NodeJS API writing to MySQL/Influx etc

Todo: Save Data to a Database

Setup 20x WeMos External Antennae’s (DONE, I ordered new factory rotated resistors)

I assumed the external antennae’s on the WeMos D1 Mini Pro’s were using the external antennae. Wrong.

I have to move 20x resistors (1 per WeMos) to switch over the the external antennae.

This will be fun as I added hot glue over the area where the resistior is to hold down the antennae.

Reading configuration files via SPIFFS

Todo

Power over Ethernet (PoE) (SKIP, WIll use plain old USB wall plugs)

Todo: Passive por PoE

Building a C# GUI for the Touch Panel

Todo (Started coding this)

Todo (Passive POE, 5v, 3.3v)?

Building the enclosures for the sensorsDesigned and ordered the PCB, FIrmware next.

Custom PCB?

Yes, See above

Backing up the Raspberry Pi M.2 Drive

This is quite easy as the M.2 Drive is connected to a USB Pliug. I shutdown the Pi and pugged int he M.2 board to my PC

I then Backed up the entire disk to my PC with Acronis Software (review here)

I now have a complete backup of my Pi on a remote network share (and my primary pc).

Version History

v0.9.63 – PCB v0.2 Designed and orderd.

v0.9.62 – 3/2/2022 Update

v0.9.61 – New Nginx, PHP, MySQL etc

v0.9.60 – Fresh Bullseye install (Buster upgrade failed)

v0.951 Email Code in PiJUice

v0.95 Added Email Code

v0.94 Added Todo Areas.

v0.93 2x Sensors hitting the API, 18x sensors ready, Air Gradient

v0.92 DHT22 and Basic API

v0.91 Password Protection

v0.9 Final Battery Setup

v0.8 OTA Updates

v0.7 Screen Enclosure

v0.6 Added Wifi Test Info

v0.5 Initial Post

Filed Under: Analytics, API, Arduino, Cloud, Code, GUI, IoT, Linux, MySQL, NGINX, NodeJS, OS Tagged With: api, ESP8266, MySQL, nginx, raspberry pi, WeMos

How to create a Private GitHub repository and access via SSH with TortiseGIT

July 17, 2021 by Simon

Here is a guide on using the GUI TortoiseGIT, GIT for Windows with GitHub.

Creating a GitHub Account

Make sure you have a GitHub account (free is OK)  https://github.com/

GitHub Main Page

Login to GitHub

Github login page

I used my defined hardware Security Key

I used my defined security key

I clicked New Repo

New Repo button

Repo Settings

  • I set Private
  • Added a readme
  • Set .gitignore for Visual Studio files
  • I had no idea what licence to select (read more on licences here)
repo settings as desired

I clicked Create repository

The repo is now ready for files

Creating RSA Keys

Now I will create an SSH key to protect communications with GitHub.

When logged into GitHub, I clicked the SSH and GPG Keys menu

I clicked New SSH Key button

New SSH Key Button

GitHub wants a public SSH Key

Add SSH Key Here

More on Generating SSH Keys

I used this command to generate a public and private SSH key

ssh-keygen -t rsa

Generate key output.

FYI: These Keys have been deleted, they have not been used beyond this demo

A Public and Private key was generated

Public and Private Key in explorer

id_github_test.pub = Public Key

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDKeAydCIpEB9EuBH/h0FbsnhUlmQT/ylKowlOWEkvl0CRZO2b7ak71GI5V4IJtVESjx/yZ3hHAhlOYp5VXbpTXv9rbKGEA12ii6d7cNOzfaAqXoHhdWqxfsfSRq0oocDVt1Inwdwsnh7tRqLHxRt0z0Gg/7m2s3sEIQqbtFkaQGjugQqs6Y9npWLd9utUcnUIRk3kajnlEeAZNVUMEn1hbX/PjODrzyI2JvGMxFzeRUTOSDWRAh6cNTM6fNZI6TLBdWHbmlZujgitiRxkWjmph31epxAkyTc0CsZ4VelU2uDgRLiWFdv+/SY2uT0/WaqZY3AlqM2GdR+WVTtiJJoh4e9ARR/ehZIkJMoWQlZa5Y8t1GnMcOa9sj3VTW5lGt1u+0JJP6IGa9T4UmxkqZRvJTDrZ1Flxcdu61is5tNLI10PYOcXz78jGSNnb8cfNzaMIHsI4oLMdurDDUz5w+5AQ9lA7gi4DE4uiX5cAsNe9jJsixB7TvCr6LF+k36Q0T3c= [email protected]

id_github_test = Private Key

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB8qp/Pde
q+G2Xrp+27vB7PAAAAEAAAAAEAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQDKeAydCIpE
B9EuBH/h0FbsnhUlmQT/ylKowlOWEkvl0CRZO2b7ak71GI5V4IJtVESjx/yZ3hHAhlOYp5
VXbpTXv9rbKGEA12ii6d7cNOzfaAqXoHhdWqxfsfSRq0oocDVt1Inwdwsnh7tRqLHxRt0z
0Gg/7m2s3sEIQqbtFkaQGjugQqs6Y9npWLd9utUcnUIRk3kajnlEeAZNVUMEn1hbX/PjOD
rzyI2JvGMxFzeRUTOSDWRAh6cNTM6fNZI6TLBdWHbmlZujgitiRxkWjmph31epxAkyTc0C
sZ4VelU2uDgRLiWFdv+/SY2uT0/WaqZY3AlqM2GdR+WVTtiJJoh4e9ARR/ehZIkJMoWQlZ
a5Y8t1GnMcOa9sj3VTW5lGt1u+0JJP6IGa9T4UmxkqZRvJTDrZ1Flxcdu61is5tNLI10PY
OcXz78jGSNnb8cfNzaMIHsI4oLMdurDDUz5w+5AQ9lA7gi4DE4uiX5cAsNe9jJsixB7TvC
r6LF+k36Q0T3cAAAWQW2CKdldNidDA+k4SncUsW+IYNcL85ir3tozfEaJHQB8icJJQpMB/
x0Y8pCpo88L3uaIeh5013yaiX4wPLt45701g0r4sBzH2UirEeyWRMGU02K2MNbGBgWUJJR
74VJ1ZjVVCptlNKoh0hebsOoVO4cdbN3FDs0D3ui/dXQb9h6D0UdyMmN9yFO7YXvtvmNyI
JEvVTJEPlt55Bill+0AQJex7lHj0z1B5sDZyjfDeMuKys+kb8ly73ZVm/59DQYiEVTAlU+
Ky70jzgwRTxhhmziGfDl+YhJI/xIYvWLhTZIw87kWyjP1fNIy4pYWLeCz+pLFDgVEI23Gl
f4P/r/OtPOf6tDu1MmHAlZ0Hw7qLTxu8sHtRxinzHcin7HcarquoouGPXPjFPPINjS/s4I
OPApLBsh0TvQdlkyTnQK2ZjNNoedLE5467sMN8sp65z+8LwaSidJkmrG38eUKWtg1qtDJN
Iyh8/5UVp+pyyu4IDVRIull6b0qmY93EcPfZVaADIKj0DDSZyacjkywSJDdupRwdCmwwKc
QB5ENvBNMU3f5IuL14F1VGickRcz2P1rLN1bndffH6MbvHRlrzKM9fymexTT1uFFTPtOnK
wzI8KYMwUynt7FDcUVTnK6OIyTxN/tfkaYWmV7AtTM5TH+GmJL+R+8QVlU+9i8LRzmjnVE
fUYc0zem/5sJqVQgJu/uSCCmtNdSVFKnSWq+/WFa1cQjnJ0baC9kuviFN/iWPZOvLJ1tyS
WsVxU+oTLCf9L0gTE8MJGFBh8QB7DVDuFFBrM3h0SsqkESKicWKL0RIPcyChQXAiQgxbSK
YAvTl6znCgVLyUHG5ggJpfKp+T57MqVUuZCPsEwAZ9ZOik3fPyVPN5a59SmCRMpY5w8N3Y
n+YgAd3tyIkzH/RbGOOGS2Oy8FyONWMXt9XnAXx2HHbvYl7nqCiSIfTSrsuAqX7CwaXk/5
8FHsx65YYWikxtb2FY5Mo+mKONXIbEbDlmFuDXYmGdi2dUyrrZMpfUMRMI4VaARH2Y1pX4
MtLfAjPPFkYF2GFnI1eUnexH36FS6DKoM5/YhQbqMlsEtzsyH2l2sosd/PgITpq94quToA
Cr12uXaYy/037pNutZXPkYD5R5vwcZgnAu8d3KOA+VzRedz1R4K4iTGgfoRRFyjz1tugvM
ruJGLDyAk09JDoqWasFtpsjjGAt9Z9s34s9PbQggFFs44ZbBvPeaD5peBbaP6bo1ekG+2B
5A+zMkeajCoKJx/W3T7oZeSL5Z9SscwsmcPRA/hP9tfXMKA93b55pHgXlu0Qbkvm3mrd05
a3RrrPCfy8dJAeW7ieR1p+BSc7t1btZfQ1n2HF994hOEkkWZ1lghXNY0/F5eP6glDnT795
ZPx00M96+6Jz7EnJOblQemfKfB3Da33MgyTMnQ/5kzQMMhk2KD7CFvzFXuVmA0oTy8Ney6
6w7BreBWYmuNUYPa+WGxkkGlivMf0a4uIcjNcPD/eyKnAp+sbRP8ZrfKFyAaZC8KWNkhPf
GA13aqMF2vIDCBTlvhMN8uGsojn7f4NVy8Frvqbm+ZqG3TwSrtgUfx2cXN1QLXvuAcFc0z
BQrh4aLy31dXpzoj0cPp3DMQF7jyp6mhcFopICrpUW+2wQKD8wOMc1BtziIpJtDXFQrh3l
QhN3/T15hnwgrt2qO/cyP0MxNLgVqN8F1+Am2gPqASyI0U/mZbh1W0ydpupcHBRc/BN37U
pc6KwT2uQ8D/b/Y8etn3QSlcTnVzZIFSSUWTHJKDnGIh/UwFj/6rESuuV+oSmH3nTVAjPT
XDTZUjd3GH7R4Ghf5dfl7eouHHLvYd58EVSZV1kGEY7W3jk74y0Vkjx9unjY1TtolIiNkD
A6h6Yt32e8MjNec0XzVHjEbXn+8=
-----END OPENSSH PRIVATE KEY-----

FYI: These Keys have been deleted, they have not been used beyond this demo

I added the Public Key to GitHub

Pased Public SSH Key

SSH Keys are listed in GitHub

Multiple SSH Keys

I create a different key per repository.

Setup Git Locally

I checked to see if the “git” command was installed on my local machine.

No Git

I will install Git from https://gitforwindows.org/ 

Git for Windows Webpage

I download Git-2.32.0.2-64-bit.exe and started the installer

Installing GIF WIzard

Folder C:\Program Files\Git

Choose a folder

Set Options (e.g I like Check for Daily updates)

GIt Options

Start Menu Folder

Start Menu

Text Editor: I like Sublime Text from https://www.sublimetext.com/3

Set Test Editor

Set an Initial Branch name

Initial Branch Name

Set 3rd party software options

3rd party options

Set HTTPS options

Open SSL

Set Line Endings preferences

Line Ending Preferences

Set Terminal Emulators preferences

Terminal Emulator settings

Set Git Pull default preferences

git pull defaults

Set Credential Manager preferences

git credential preferences

Set Extra Options

Set Options

Experimental Options

Opt out of experimental options

Installing

Installing

First Launch

First launch

Git is installed

Install Tortoise GIt

Visit https://tortoisegit.org/

Tortoiuse git website

Download Gif (64bit)

Download options

I started the installer.

Setup Wizard.

Licence Agreement

Licence Agreement

SSH Type

set ssh type

Components

Componentts

Install

Installing (Wizard)

Install


Language: English

 

English

Shell Extension

Shell Integration

I checked for a known git path.

Git path check

I set my desired git username and email

Default git username

I set desired SSH settings

SSH Settings

Folder for Code Repositories

I create C:\Code\MyTestRepo

C:\Code

Before I can clone a repository I need o set the past to SSH in TortoiseGit.

I right-clicked on C:\Code\MyTestRepo and selected TortiseGit\Settings

TortoiseGit Settings

I expanded the Network Node and set the following as the SSH Client

“C:\Program Files\TortoiseGit\bin\TortoiseGitPLink.exe”

SSH Client Set

I saved the Settings.

Clone a GitHub Repository via git and Tortoise GIT

Now I can clone a repositor to C:\Code\MyTestRepo, 

I right clicked on C:\Code\MyTestRepo in explorer and clicked Git Clone

I added by GIT URL (Obtained from GitHub), I also set the path for the Private Key I created earlier.

Git Clone

I was informed that the key is in the wrong format

Wrong Format Error

I need to convert the RAS Private Key to a Putty PPK Key

Convert an RSA Key to a Putty PPK with PuuttyGen

I opened the Open Putty Gen

https://www.puttygen.com/

I click Load and select the id_github_test private key I created earlier

Load private key

I entered my private key password

Private Key Password.

The private key loaded.

Private Key Loaded

Now I can export the private key to a PPK format

Export as PPK

Clone (with a PPK Private Key)

Getting back to cloning a repository I right-clicked on C:\Code\MyTestRepo

I set the PPK private key

Clone with PPK

I entered the password

Enter password

I accepted the key

Accpet key

The Repository started cloning.

Repository Cloning

Creating a Quick Visual Studio Project

I created a quick Visual Studio project and saved it to C:\Code\MyTestRepo\Hello World

New Visual Studio project

Visual Studio files were visible in C:\Code\MyTestRepo

C:\Code\MyTestRepo

I Commit the new files to the repository (main branch)

Commit

I selected desired files to commit

Commit

Files were added

I right-clicked on C:\Code\MyTestRepo and selected TortoiseGit\Push

Push Dialog

Files are now visible in GitHub

Awesome

Setup on Multiple Machines

I set up Git on multiple machines, cloned, made chances, committed those changes and pushed.  I was able to Sync down those changes to each machine.

Good advice on Using Git

  • Git Guides – git push (github.com)
  • What is git commit, push, pull, log, aliases, fetch, config & clone | by Ameet Prajapati | MindOrks | Medium
  • GitHub 101 — Introduction to GitHub for Newbies | by Arerosuoghene Wisdom | Medium

Happy Coding

Filed Under: Code, Git, GitHub, Uncategorized, Windows Tagged With: git, GitHub, gui, TortoiseGit, windows

Adafruit HUZZAH32 ESP32 Feather + RTC + Alpha-Numeric LED + Solenoid Zen Clock

September 10, 2020 by Simon

This IoT project is under construction.

My goal is to have a Microcontroller strike a Singbowl (I purchased from https://singbowls.com/) every hour between 7AM and 9PM (every day) to remind my kids to be more mindful and stay in the present moment.  I had a minor stroke 3 years ago and I can tell you that mindfulness is very important.

The Microcontroller I will use is an ESP-32 running off 5 volts (DC) that will have a solid-state real-time clock and each hour a solenoid will be activated and strike the sing bowl (making a nice noise)

Extra strikes will wake the kids up on school mornings and at their bedtime. 

Rough idea of the Zen clock

Disclaimer: I am not a qualified electrician or electronics expert. All advice is given “as is” and without guarantees or defects. In software coding or electronics there is always edge cases and limits of code or circuits. I did not get a discount for the Sing bowl to promote them and this is not a plug for Adafruit.

Why?

Ever since I pulled apart my first remote control Christmas toy at 10 years old I have been fascinated with Electronics. At 14 year old, I became fascinated with Computer Games and at 16 years old I became fascinated with computer programming.

40 years later (almost 25-year’s working as a software engineer/programming) I now have time to return to a childhood passion and discover electronic circuits are and how to make them.

Better still I can control the circuits with computer code.

Sing Bowl Sound

Here is a video recording of the sound of the Sing bowl before purchased it (video kindly made by Anup before purchase). Thanks, Anup for answering my silly questions.

I am calling it a Zen bowl as my Kids know Zen. Apologies Anup.

I found Anup and https://singbowls.com/ by searching YouTube one night and I found this 9-year-old video.

Parts

Below are parts I am using.

  1. Adafruit HUZZAH32 – ESP32 Feather Board (pre-soldered)
  2. Adafruit: DS3231 Precision RTC FeatherWing – RTC Add-on For Feather Boards
  3. Adafruit 0.54″ Quad Alphanumeric FeatherWing Display – Green
  4. Particle FeatherWing Trippler
  5. Adafruit Prototyping Add-on Board for Feather
  6. 1x 12 Solenoid (12V 8Amp)
  7. 1x N-CHANNEL MOSFET 60V 30A
  8. Fallback Diode (1N4004 1A 400V Diode – Pack of 4)
  9. Box – Hand Made (TBA)
  10. Resistors, LEDs, Headers, Buttons (TBA)

I have ordered the bulk of the parts from Australia (e.g https://core-electronics.com.au/). Core Electronics are awesome as they have great chat support on their website and answer silly questions from me.

Pre Assembled v Soldering

You may be able to buy all pre-assembled parts or you can solder the parts where needed.  I have a cheap Soldering iron from Jaycar.

I decided to solder the Clock and Display but not the ESP-32.  I used Lead-free solder and Rosin flux.

Soldering can be fun but with you need good close up vision or you miss pins like me.

Missed soldering on a pin

I had pins that needed touching up as they has too little solder contact

Pin with low contact

After a few touch ups and close inspections I was happy with solder joints.

I am happy with these solder joints

All feather boards fit the tripper board after 100 odd solder connections (including the screen joints not pictured)

After solder joints were made and I cleaned them up with pure Isopropyl Alcohol I tested each joint with my multimeter to ensure each joint was not connected to nearby joints.

Multimeter testing joints

I tripped tested each connection as I did not want issues later.

Multimeter setting

Installing the Arduino IDE Software

On Windows, go to https://www.arduino.cc/en/Main/Software

Download ARDUINO 1.8.13+ (for Windows)

Arduino Website - Download

I Installed the Software

During the setup ensure you install the USB Driver

Install the USB Driver

Also make sure you agree to the device install prompts

  1. Adafruit COM Port

2. Arduino USB Driver(s)

and

Now the Arduino IDE Will be installed

Blank Arduino IDE

Installing the Adafruit SiLabs CP2104 Driver

I need to install the SiLabs CP2104 Driver.

This can be obtained from the Adafruit website here (https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/using-with-arduino-ide).

This redirects to here: https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

Download the “Windows 10 Universal – VCP Software): CP210x_Universal_Windows_Driver.zip

CP210x Driver

Extract the contents of CP210x_Universal_Windows_Driver.zip

Extract the ZIP FIle

Run CP210xVCPInstaller_x64.exe as Administrator

Run CP210xVCPInstaller_x64.exe as Administrator

I Installed the Drivers

Driver Installed

Installing the Adafruit ESP Feather in the Arduino IDE Boards Manager

The Espressif Arduino GitHub repository details how you can add the EBS32boards to the Arduino Boards Manager. Scroll down to “Installation Instructions”

Go to https://github.com/espressif/arduino-esp32#using-through-arduino-ide

Open the Arduino IDE Application and click File then Preferences

Preferences Screen

I will follow the steps here https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/boards_manager.md

Under “Additional Boards Manager URL: Add “https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json”

Add Boards URL(s)

I closed the Preferences dialogue

I clicked the Tools menu then Boards then Board Manager

Boards Manager

I then search for “esp32”

esp32

I clicked Install

Click the list item then the Install button will appear.

This could take a while,

Installing ESP32 Boards Progress Bar

Installing Boards Progress Bar

Installing Tools Progress Bar

Installing Tools Progress Bar

Updating Libraries

From time to time (if the Arduino IDE does not prompt you) you may need to open the Library Manager and check for updatable libraries to download

Uneatable Combo Box

Always Install the latest version of each library

Some libraries may need dependencies installed (always click “Install All”)

Install All

Selecting the Adafruit Feather in the Arduino IDE

In the Arduino IDE, I went to the Tools Menu then Board the ESP-32 Arduino then select Adafruit Feather ESP-32 Feather to choose that board.

Choose your board

I will need to also define the COM port that the ESP-32 is using.  I do that by opening Computer Management/Device Manager on Windows and expand the Ports (COM & LPT), plug in the ESP-32 and see what COM port appears.

Om POrt Inserted

Then I can set that COM port in the Arduino IDE.

In the bottom right of the Arduino IDE confirm that your ESP-32 and COM port match

Board and Com Port Verify

Writing your first sketch to the ESP32

To ensure the soldering is OK and that the Arduino IDE is OK and connection to the board let’s use a simple sketch to replace the default blink sketch.

In the Arduino IDE click the File menu then Examples then 01.Basic  then Blink

Blink Sketch

Code

/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

I changed the first 1000 in the loop to 5000 to make the blink slower than the one from the factory on the board.

Click the Verify then Upload button to confirm you can write to the ESP-32.

Upload Sketch

Adding the DS3231 Precision RTC Library to the Arduino IDE

Read here to learn about the DS3231 RTC https://learn.adafruit.com/ds3231-precision-rtc-featherwing

I just need to add a CR1220 3v Battery. One battery should last about 5 years.

Only 4 pins (https://learn.adafruit.com/ds3231-precision-rtc-featherwing/pinouts) are used to communicate with the ESP32

I can use the Arduino Library manager to find the RTCLib library

Library Manager

I also need to install the dependencies.

Install Dependancies

Connecting the DS3231 Precision RTC Library to the ESP32

I connected the RTC Feather to the EBS-32.

Now I can open the example ds3231 sketch and write it to the ESP-32.

In the Arduino IDE click the File menu then Examples then RTCLib  then ds3231

ds3231 sketch

Code

// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include "RTClib.h"

RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

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

#ifndef ESP8266
  while (!Serial); // wait for serial port to connect. Needed for native USB
#endif

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  // When time needs to be re-set on a previously configured device, the
  // following line sets the RTC to the date & time this sketch was compiled
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}

void loop () {
    DateTime now = rtc.now();

    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();

    Serial.print(" since midnight 1/1/1970 = ");
    Serial.print(now.unixtime());
    Serial.print("s = ");
    Serial.print(now.unixtime() / 86400L);
    Serial.println("d");

    // calculate a date which is 7 days and 30 seconds into the future
    DateTime future (now + TimeSpan(7,12,30,6));

    Serial.print(" now + 7d + 30s: ");
    Serial.print(future.year(), DEC);
    Serial.print('/');
    Serial.print(future.month(), DEC);
    Serial.print('/');
    Serial.print(future.day(), DEC);
    Serial.print(' ');
    Serial.print(future.hour(), DEC);
    Serial.print(':');
    Serial.print(future.minute(), DEC);
    Serial.print(':');
    Serial.print(future.second(), DEC);
    Serial.println();

    Serial.print("Temperature: ");
    Serial.print(rtc.getTemperature());
    Serial.println(" C");

    Serial.println();
    delay(3000);
}

After flashing the ESP-32 I could see the ESP-32 was sending back data from the Microcontroller.  

Date Output to serial

Adding the QUAD Alphanumeric Feather Wing Display to the Arduino IDE

The Alpha-Numeric display is a more complex so time to read some documentation.

  • Product Page: https://learn.adafruit.com/14-segment-alpha-numeric-led-featherwing
  • Pinouts: https://learn.adafruit.com/14-segment-alpha-numeric-led-featherwing/pinouts
  • Assembly: https://learn.adafruit.com/14-segment-alpha-numeric-led-featherwing/assembly
  • Usage: https://learn.adafruit.com/14-segment-alpha-numeric-led-featherwing/usage

I can download the library to drive this display here: https://github.com/adafruit/Adafruit_LED_Backpack/archive/master.zip

I downloaded the library.

Snip “Rename the uncompressed folder Adafruit_LEDBackpack. Check that the Adafruit_LEDBackpack folder contains Adafruit_LEDBackpack.cpp and Adafruit_LEDBackpack.h Place the Adafruit_LEDBackpack library folder your arduinosketchfolder/libraries/ folder.”

Library Manager: https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use/library-manager

Alpha Numeric Library

Testing the QUAD Alphanumeric Feather Wing Display to the ESP32

In the Arduino IDE click the File menu then Examples then Adafruit LED Backpack Library then quadalphanum

I connected the Alpha Numeric Display to the EPS-32 and uploaded the sketch.

Code

// Demo the quad alphanumeric display LED backpack kit
// scrolls through every character, then scrolls Serial
// input onto the display

#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4();

void setup() {
  Serial.begin(9600);
  
  alpha4.begin(0x70);  // pass in the address

  alpha4.writeDigitRaw(3, 0x0);
  alpha4.writeDigitRaw(0, 0xFFFF);
  alpha4.writeDisplay();
  delay(200);
  alpha4.writeDigitRaw(0, 0x0);
  alpha4.writeDigitRaw(1, 0xFFFF);
  alpha4.writeDisplay();
  delay(200);
  alpha4.writeDigitRaw(1, 0x0);
  alpha4.writeDigitRaw(2, 0xFFFF);
  alpha4.writeDisplay();
  delay(200);
  alpha4.writeDigitRaw(2, 0x0);
  alpha4.writeDigitRaw(3, 0xFFFF);
  alpha4.writeDisplay();
  delay(200);
  
  alpha4.clear();
  alpha4.writeDisplay();

  // display every character, 
  for (uint8_t i='!'; i<='z'; i++) {
    alpha4.writeDigitAscii(0, i);
    alpha4.writeDigitAscii(1, i+1);
    alpha4.writeDigitAscii(2, i+2);
    alpha4.writeDigitAscii(3, i+3);
    alpha4.writeDisplay();
    
    delay(300);
  }
  Serial.println("Start typing to display!");
}


char displaybuffer[4] = {' ', ' ', ' ', ' '};

void loop() {
  while (! Serial.available()) return;
  
  char c = Serial.read();
  if (! isprint(c)) return; // only printable!
  
  // scroll down display
  displaybuffer[0] = displaybuffer[1];
  displaybuffer[1] = displaybuffer[2];
  displaybuffer[2] = displaybuffer[3];
  displaybuffer[3] = c;
 
  // set every digit to the buffer
  alpha4.writeDigitAscii(0, displaybuffer[0]);
  alpha4.writeDigitAscii(1, displaybuffer[1]);
  alpha4.writeDigitAscii(2, displaybuffer[2]);
  alpha4.writeDigitAscii(3, displaybuffer[3]);
 
  // write it out!
  alpha4.writeDisplay();
  delay(200);
}

It worked

Combining the Blink + Clock+ Alphanumeric Display into Ome Sketch

Now I can combine all sketches into one and have the Alpha Numeric display the time

Code 

// Simon Fearby - 10th Sep 2020


// Alpha Numeric Screen Setup
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
Adafruit_AlphaNum4 greenScreen = Adafruit_AlphaNum4();

//RTC Setup
#include "RTClib.h"
RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};


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

  //Alpha Num Setup
  greenScreen.begin(0x70);  // pass in the address
  //15 is Highest Brightness
  //0 is Lowest  Brightness
  greenScreen.setBrightness(7);
  
  greenScreen.clear();

  //RTC Setup
  #ifndef ESP8266
    while (!Serial); // wait for serial port to connect. Needed for native USB
  #endif
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  // When time needs to be re-set on a previously configured device, the
  // following line sets the RTC to the date & time this sketch was compiled
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

  
  // Blink Setup
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  //Led
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(100);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(100);                       // wait for a second

  //RTC
    DateTime now = rtc.now();
    Serial.print(now.day(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.year(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.println();
    /*
    Serial.print(" since midnight 1/1/1970 = ");
    Serial.print(now.unixtime());
    Serial.print("s = ");
    Serial.print(now.unixtime() / 86400L);
    Serial.println("d");
    // calculate a date which is 7 days and 30 seconds into the future
    DateTime future (now + TimeSpan(7,12,30,6));
    Serial.print(" now + 7d + 30s: ");
    Serial.print(future.year(), DEC);
    Serial.print('/');
    Serial.print(future.month(), DEC);
    Serial.print('/');
    Serial.print(future.day(), DEC);
    Serial.print(' ');
    Serial.print(future.hour(), DEC);
    Serial.print(':');
    Serial.print(future.minute(), DEC);
    Serial.print(':');
    Serial.print(future.second(), DEC);
    Serial.println();
    */

  //Default display
  greenScreen.writeDigitAscii(0, '0');
  greenScreen.writeDigitAscii(1, '0');
  greenScreen.writeDigitAscii(2, '0');
  greenScreen.writeDigitAscii(3, '0');

  
//Hour
  switch (now.hour()) {
    case 0:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '2');
      break;
    case 1:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '1');
      break;
    case 2:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '2');
      break;
    case 3:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '3');
      break;
    case 4:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '4');
      break;
    case 5:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '5');
      break;
    case 6:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '6');
      break;
    case 7:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '7');
      break;
    case 8:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '8');
      break;
    case 9:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '9');
      break;
    case 10:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '0');
      break;
    case 11:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '1');
      break;
     case 12:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '2');
      break;
    case 13:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '3');
      break;
    case 14:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '4');
      break;
    case 15:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '5');
      break;
    case 16:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '6');
      break;
    case 17:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '7');
      break;
    case 18:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '8');
      break;
    case 19:
      greenScreen.writeDigitAscii(0, '1');
      greenScreen.writeDigitAscii(1, '9');
      break;
    case 20:
      greenScreen.writeDigitAscii(0, '2');
      greenScreen.writeDigitAscii(1, '0');
      break;
    case 21:
      greenScreen.writeDigitAscii(0, '2');
      greenScreen.writeDigitAscii(1, '1');
      break;
    case 22:
      greenScreen.writeDigitAscii(0, '2');
      greenScreen.writeDigitAscii(1, '2');
      break;
    case 23:
      greenScreen.writeDigitAscii(0, '2');
      greenScreen.writeDigitAscii(1, '3');
      break;
   case 24:
      greenScreen.writeDigitAscii(0, '2');
      greenScreen.writeDigitAscii(1, '4');
      break;
   default:
      greenScreen.writeDigitAscii(0, '0');
      greenScreen.writeDigitAscii(1, '0');
     break;
  }


  //Minute
  switch (now.minute()) {
    case 0:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '0');
      break;
    case 1:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '1');
      break;
    case 2:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 3:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '3');
      break;
    case 4:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '4');
      break;
    case 5:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '5');
      break;
    case 6:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '6');
      break;
    case 7:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '7');
      break;
    case 8:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '8');
      break;
    case 9:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '9');
      break;
    case 10:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '0');
      break;
    case 11:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '1');
      break;
     case 12:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 13:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '3');
      break;
    case 14:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '4');
      break;
    case 15:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '5');
      break;
    case 16:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '6');
      break;
    case 17:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '7');
      break;
    case 18:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '8');
      break;
    case 19:
      greenScreen.writeDigitAscii(2, '1');
      greenScreen.writeDigitAscii(3, '9');
      break;
    case 20:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '0');
      break;
    case 21:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '1');
      break;
    case 22:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 23:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '3');
      break;
     case 24:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '4');
      break;
    case 25:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '5');
      break;
    case 26:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '6');
      break;
    case 27:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '7');
      break;
    case 28:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '8');
      break;
    case 29:
      greenScreen.writeDigitAscii(2, '2');
      greenScreen.writeDigitAscii(3, '9');
      break;
    case 30:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '0');
      break;
    case 31:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '1');
      break;
    case 32:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 33:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '3');
      break;
    case 34:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '4');
      break;
    case 35:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '5');
      break;
    case 36:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '6');
      break;
    case 37:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '7');
      break;
    case 38:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '8');
      break;
    case 39:
      greenScreen.writeDigitAscii(2, '3');
      greenScreen.writeDigitAscii(3, '9');
      break;
    case 40:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '0');
      break;
    case 41:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '1');
      break;
    case 42:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 43:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '3');
      break;
    case 44:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '4');
      break;
    case 45:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '5');
      break;
    case 46:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '6');
      break;
    case 47:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '7');
      break;
    case 48:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '8');
      break;
    case 49:
      greenScreen.writeDigitAscii(2, '4');
      greenScreen.writeDigitAscii(3, '9');
      break;
    case 50:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '0');
      break;
    case 51:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '1');
      break;
    case 52:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 53:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '2');
      break;
    case 54:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '4');
      break;
    case 55:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '5');
      break;
    case 56:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '6');
      break;
    case 57:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '7');
      break;
    case 58:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '8');
      break;
    case 59:
      greenScreen.writeDigitAscii(2, '5');
      greenScreen.writeDigitAscii(3, '9');
      break;

   default:
      greenScreen.writeDigitAscii(2, '0');
      greenScreen.writeDigitAscii(3, '0');
     break;
  }


  greenScreen.writeDisplay();
    
    //Serial.print("Temperature: ");
    //Serial.print(rtc.getTemperature());
    //Serial.println(" C");
    //Serial.println();

  delay(800);
}

Video

Triggering a Solenoid Every Hour and making a sound

I have created a test circuit to test the MOSFET (first with a 12V motor then a solenoid), I am using the Fritzing program to create the circuit.

Apologies the 12V power source is shown as AA- batteries this is because I can’t find the right Fritzinbg part to indicate a DC power

Here is the Arduino IDE code to drive the motor

int led = 13;       //Define the onboard LED
 PIN
int mosfet = 5;     //Define the MOSFET Trigger
 PIN

void setup() {
  pinMode(led, OUTPUT);
  pinMode(mosfet, OUTPUT);
}

void loop() {
  
  //Turn ON the LED
  digitalWrite(led, HIGH);
  //Turn ON the MOSFET
  digitalWrite(mosfet, HIGH);
  //Wait half 3 seconds
  delay(3000);

  //Turn OFF the LED
  digitalWrite(led, LOW);
  //Turn OFF the MOSFET
  digitalWrite(mosfet, LOW);
  //Wait 3 Seconds
  delay(3000);

  //Loop
}

Here is a video of this circuit working

I will eventually move this over to my in progress ESP-32 Micro Controller.

When I move to the Solenoid (12v 8 A) I will need to turn on the Solenoid for mo more than  a second

  //Turn ON the MOSFET
  digitalWrite(mosfet, HIGH);

 //Wait a half a seconds
  delay(500);

Power Usage

Power usage is low and Micro Controller, Clock and Display only used 0.048A, there is still room to make this microcontroller use less power.

My Wireless Completer Headphones Dongle  I use on my PC uses 0.07A

Safety Features

Safety features are in progress.

  • Fuse for power protection
  • Multiple Thermistor’s to sense the temperature of the Solenoid 
  • Heatsink for the MOSFET
  • etc TBA

Where I purchased Parts from in Australia

This is not a plug of affiliate links.

  • Adafruit HUZZAH32 – ESP32 Feather Board (pre-soldered)
  • Adafruit: DS3231 Precision RTC FeatherWing – RTC Add-on For Feather Boards
  • Particle FeatherWing Trippler
  • Adafruit 0.54″ Quad Alphanumeric FeatherWing Display – Green
  • Adafruit Prototyping Add-on Board for Feather
  • 1x 12 Solenoid (12V 8Amp)
  • 1x N-CHANNEL MOSFET 60V 30A
  • Fallback Diode (1N4004 1A 400V Diode – Pack of 4)
  • Thermistors
  • Box (Tba)
  • TBA: Resistors, LEDS, Headers

 

Links

  • https://singbowls.com/
  • Adafruit HUZZAH32 – ESP32 Feather Related
    • Overview: https://learn.adafruit.com/adafruit-huzzah32-esp32-feather
    • Pinout: https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/pinouts
    • Assembly: https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/assembly
    • Power: https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/power-management
    • IDE: https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/using-with-arduino-ide
    •  

v1.2 Added Prototype Wiring Diagrams and safety features

Filed Under: Arduino, Code, ESP32, IoT Tagged With: Adafruit, ESP32, Featgher, RTC

How to code PHP on your localhost and deploy to the cloud via SFTP with PHPStorm by Jet Brains

March 31, 2019 by Simon

This is a quick guide that will show you how you can connect to a cloud server via SFTP with the PHPStorm IDE from Jet Brians and deploy files from your localhost to the cloud. This is my opinion, I am not paid to promote PHPStorm or UpCloud.

Pre-Requisites/Assumptions

This guide will assume you already have (or know how to)..

  • Buy a domain name and point it’s DNS to a server (I use Namecheap.com for buying domains)
  • Buy and deploy a server in the cloud. I have used AWS, Digital Ocean, Vultr but now use UpCloud for deploying fast self-managed servers. Read this guide here to see how I create a server from scratch on Up Cloud.
  • Setup SSH access to your server and configure a firewall.
  • You have or know how to set up PHP and Web Servers and configure them on your localhost and remote server (guides here, here, here, here, here and here).
  • etc ( check out all my guides here https://fearby.com/all )

I am using Windows 10 Home (with IIS Web Server (document root redirected to S:\Code\) and a pre built Ubuntu Cloud servers.

IIS pointing to S:\Code

Why no FTP? I do not create FTP servers on my serves to increase security and I only access servers via SSH via white-listed IP’s and then authenticate with hardware 2FA keys from YubiCo (read me 2FA guide here and also how to secure *nix servers and WordPress with 2FA).

Background

2 years ago I used to use the Cloud 9 IDE to connect to, and code files on cloud servers and life was good. I could configure and connect to servers, drag and drop files, run bash scripts from a web page and close the Cloud 9 browsers tabs, travel hundreds of kilometres and log back into C9 and all code and bash scripts would reappear.

Here is the Cloud 9 IDE showing code on the left and a Browser on the right.

C9.IDE showing code on the left and web page on the right

With Cloud 9 code could be easily accessed, edited and run.

See screenshot of code running from a Cloud 9 hosted server with properties windows on the right.

C9 IDE showing  a bash terminal windows and code

Regrettably, I cancelled my $9/m subscription to Cloud 9 after a minor stroke and since then I have gone back to a terminal screen to code and transfer files. In the last 2 years.

Screenshot of the putty program connected to a Ubuntu box editing a file with nano

Uploading and downloading files on mass is painful via pure SSH.

AWS has since purchased Cloud 9 and I am not sure if it will ditch support of non-AWS servers in the future. AWS is good but servers are very expensive for what you get IMHO. I have found Disk IO on UpCloud is awesome (also UpCloud support is great (I am not paid to say that)).

PHPStorm IDE?

A quick Google of IDE’s like Cloud 9 mentioned PHPStorm from Jet Brains. I have used IntelliJ IDEA from Jet Brains before and PHPStorm seems to be very popular.

Go to
https://www.jetbrains.com/phpstorm/ and see the features of PHPStorm

Watch PHPStorm in action

Whats new in PHPStorm 2019.1

Install PHPStorm

Visit https://www.jetbrains.com/phpstorm/download/ and download and install PHPStorm (free trial 30 days)

System requirements

  • Microsoft 10/8/7/Vista/2003/XP (incl. 64-bit)
  • 2 GB RAM minimum
  • 4 GB RAM recommended
  • 1024×768 minimum screen resolution

Pricing

PHPStorm is $8.90/m for individual use (or $19.90/m commercial). For the first 12 months of uninterrupted subscription payments qualify you for receiving a perpetual fallback license (20% discount for an uninterrupted subscription for a 2nd year, 40% discount for an uninterrupted subscription for 3rd year onwards).

PHPStorm work on Windows, OSX or Linux. This great an I use Windows locally and Linux remotely but I’m keen to use Linux locally to match local and remote dev environments.

Official PHPStorm Pricing Page:
https://www.jetbrains.com/phpstorm/buy/#edition=commercial

fyi: Jet Brains has free licencing for individual use for Students and faculty members.

Creating a Project

Open PHPStorm and select “Create New Project”.

Create New Project screen

Choose a project type on the left (e.g “PHP Empty Project“) and choose a location to save too (I chose “S:\code\php001) on my local machine. I chose “S:\code\php001” on my local machine.

New Project screenshot asking for a name and save location

Choose a folder to save to.

Choose a project and location to save to locally

Click “OK” to create the project.

PHPStorm will have created a project for you. You will notice a “.idea“folder under the location you saved with these files.

  • misc.xml
  • modules.xml
  • php001.xml
  • wordspace.xml

Do not delete these files.

Creating your first PHP file

You can right click on the project root and select New then PHP File

Right click on the root in the tree view then new PHP File

Or clicking the File then New menu choosing PHP File.

File new PHP File dialog

Name the file (e.g index.php)

Naming a file index.php

The file has been created and its available in my localhost web server.

Screenshot showing PHPStorm with index.php, S:\Code showing index.php and http://localhpst/php001/index.php loading

Creating a Deploy Target

Now we need to specify a deploy target in PHPStorm to push the file changes to the cloud. Backup your server (yes backup your server just in case).

Open your PHPStorm project and click Tools, Deployment and then Configuration.

Click Tools, Deployment and then Configuration.

Click the plus icon near the top left and choose SFTP

Screenshot showing add new deployment server (SFTP)

Name the deployment target (e.g “server (project)”)

Screenshot of an input box showing a server name
  • Enter your “server name” or IP and port
  • Enter your “ssh username” (ensure the SSH user had write access to the wwwroot folder and the web server can read the files written by this user)
  • Under password I chose “Key pair OpenSSH or Putty (as I had SSH details already setup in Putty details
  • You can add your ppk private key from Putty (use the puttygen program to conbvert ssh public and private kets to ppk format)
  • If you have a passphrase on your SSH key add it now
  • Enter your web servers remote path (for the project)
  • Enter your web server URL
Screenshot showing a server name, port, username, password, ssh file passphrase, root path and web server url.

I did SSH to my remote server and created the destination folder. This will ensure I can deploy code here (PHPStorm does not create the remote path fpor you ).

mkdir /wwwroot/php001
chown -R www-data:www-data /wwwroot/php001/

Click Test Connection

Test Successful screenshot

No we need to click the Mappings tab and add a mapping.

  • Local path is your local path
  • Deployment path is / (the web root path is carried forward from the previous tab)
  • Web path is the web path that is entered in the browser
Screenshot showing a manual file mapping of local and remote file locations

Click Add New Mapping. Now we are ready to deploy

Deploying code to the cloud

I right clicked on the root note in PHPStorm and created an index.php file.

Creating an index.php file by file new

I edited the index.php on my local machine and then click the Tools then Deployment and choose “Upload to fearby.com (php001)” menu.

Manual upload available in Tools menu then Deployment menu

The File Transfer output window showed the transfer progress.

Screenshot showing the file transfer window output saying the file uploaded.

I loaded https://fearby.com/php001/index.php in Google chrome. It worked.

Screenshot showing https://fearby.com/php001/index.php loaded in a bowser

Don’t forget to turn off Automatic uploads under Tools, Deployment menu.

'Screenshot showing Automatic updated turned on

Now when I create new files or change existing files they will auto upload.

Sourc Control

I will add this soon.

Shell Command

You can also open an SSH console to the server and run commands

e.g zip files

zip -r backup.zip .

I can also open a folder window in PHPStorm and show all remote files by clicking Tools then Deployment then Show Remote Files, Zip files can be easily downlaoded or other files uploaded. Nice.

Screenshot showing remote files

Linux Client

I will review the Linux PHPStorm client soon.

Troubleshooting

Watch the Official guide on Deployment and Remote Hosts in PhpStorm – PhpStorm Video Tutorial

Good Luck. I hope this guide helps someone.

Version

1.2 Removed advertisements

1.1 Minor Updates

1.0 Initial Version

Filed Under: 2FA, Backup, Cloud, Code, Git, GUI, IDE, Linux, SSH

Setup two factor authenticator protection at login on Ubuntu or Debian

October 14, 2018 by Simon

This is a quick post that shows how I set up two-factor authenticator protection at login on Ubuntu or Debian

Aside

If you have not read my previous posts I have now moved my blog to the awesome UpCloud host (signup using this link to get $25 free UpCloud VM credit). I compared Digital Ocean, Vultr and UpCloud Disk IO here and UpCloud came out on top by a long way (read the blog post here). Here is my blog post on moving from Vultr to UpCloud.

Buy a domain name here

Domain names for just 88 cents!

Now on with the post.

Backup

I ensured I had a backup of my server. This is easy to do on UpCloud. If something goes wrong I will rollback.

Sever Backup Confirmed

Why Setup 2FA on SSH connections

1) Firewalls or whitelists may not protect you from detection.

2) SSH authorisation bypass bugs may appear.

I’ve just relased libssh 0.8.4 and 0.7.6 to address CVE-2018-10933. This is an auth bypass in the server. Please update as soon as possible! https://t.co/Qhra2TXqzm

— Andreas Schneider (@cryptomilk) October 16, 2018

2FA authorisation is another lube of defence.

Yubico Yubi Key

Read my block post here to learn how to use the Yubico YubiKey NEO hardware-based two-factor authentication device to improve authentication and logins to OSX and software

Timezone

It is important that you set the same timezone as the server you are trying to secure two 2FA. I can run this command on Linux to set the timezone.

On Debian, I set the time using this guide.

dpkg-reconfigure tzdata

Check the time command

> timedatectl
> Local time: Tue 2019-06-25 16:45:20 UTC
> Universal time: Tue 2019-06-25 16:45:20 UTC
> RTC time: Wed 2019-06-26 02:37:44
> Time zone: Etc/UTC (UTC, +0000)
> Network time on: yes
> NTP synchronized: yes
> RTC in local TZ: no

sudo hwclock --show

I set the timezone

> sudo timedatectl set-timezone Australia/Sydney

I confirmed the timezone

> timedatectl
> Local time: Wed 2019-06-26 02:47:42 AEST
> Universal time: Tue 2019-06-25 16:47:42 UTC
> RTC time: Wed 2019-06-26 02:40:06
> Time zone: Australia/Sydney (AEST, +1000)
> Network time on: yes
> NTP synchronized: yes
> RTC in local TZ: no

I installed a npt time server

I followed this guide to install an NTP time server (failed at: ntpdate linuxconfig.ntp) and this guide to manually sync

I installed the Google Authenticator app

sudo apt install libpam-google-authenticator
sudo apt-get install libpam-google-authenticator

Configure Google Authenticator

Run google-authenticator and answer the following questions

Q1) Do you want authentication tokens to be time-based (y/n): Y

You will be presented with a token you can add to the Yubico Authenticator or other authenticator apps,

2FA Code

TIP: Write down any recovery codes displayed

Scan the code with your 2FA Authenticator app (e.g Google Authenticator, Yubico Authenticator or freeOTP from https://freeotp.github.io)

Scan 2FA Code

The 2FA code is now available for use in my YubiCo Authenticator app

Authenticator App Ready

Q2) Do you want me to update your “/root/.google_authenticator” file? (y/n): Y

Q3) Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n): Y

Q4) By default, a new token is generated every 30 seconds by the mobile app.
In order to compensate for possible time-skew between the client and the server,
we allow an extra token before and after the current time. This allows for a
time skew of up to 30 seconds between the authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) y: Y

Q5) If the computer that you are logging into isn’t hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n): Y

Review Google Authenticator Config

sudo nano ~/.google_authenticator

You can change this if need be.

sudo nano ~/.google_authenticator

Edit SSH Configuration (Authentication)

sudo nano /etc/pam.d/sshd

Add the line below the line “@include common-auth”

auth required pam_google_authenticator.so

Comment out the following line (this is the most important step, this forces 2FA)

#@include common-auth

Edit SSH Configuration (Challenge Response Authentication)

Edit the ssh config file.

sudo nano /etc/ssh/sshd_config

Search For

ChallengeResponseAuthentication

Set this to

yes

Ensure the following line exists

UsePAM yes

Add the following line

AuthenticationMethods publickey,password publickey,keyboard-interactive

Edit Common Auth

sudo nano /etc/pam.d/common-auth

Add the following line before the line that says “auth [success=1 default=ignore] pam_unix.so nullok_secure”

auth required pam_google_authenticator.so

Restart the SSH service and test the codes in a new terminal before rebooting.

TIP: Do not exit the working connected session and you may need it to fix issues.

Restart the SSH service a tets it

/etc/init.d/ssh restart
[ ok ] Restarting ssh (via systemctl): ssh.service.

If you have failed to set it up authenticator codes will fail to work.

Failed attempts

Further authentication required
Using keyboard-interactive authentication.
Verification code:
Using keyboard-interactive authentication.
Verification code:
Using keyboard-interactive authentication.
Verification code:

When it is configured OK (at login SSH connection) I was prompted for further information

Further Information required
Using keyboard-interactive authentication
Verification Code: ######
[email protected]#

I am now prompted at login to insert a 2FA token (after inserting my YubiKey)

Working 2FA in Unix

Turn on 2FA on other sites

Check out https://www.turnon2fa.com and tutorials here.

I hope this guide helps someone.

Please consider using my referral code and get $25 UpCloud VM credit if you need to create a server online.

https://www.upcloud.com/register/?promo=D84793

Ask a question or recommend an article

[contact-form-7 id=”30″ title=”Ask a Question”]

Revision History

V1.4 June 2019: Works on Debian 9.9

V1.3 turnon2fa.com

V1.2 ssh auth bypass

v1.1 Authenticator apps

v1.0 Initial Post

Filed Under: 2FA, 2nd Factor, Auth, Authorization, Code, Debian, Security, Ubuntu, UpCloud, Yubico, YubiKey Tagged With: app, at, authenticator, debian, factor, login, on, or, Protection, security, Setup, two, ubuntu, Yubico, YubiKey

Useful Java FX Code I use in a project using IntelliJ IDEA and jdk1.8.0_161.jdk

September 15, 2018 by Simon

This is some useful Java FX Code I use in a project using IntelliJ IDEA and jdk1.8.0_161.jdk. I am sharing this code here for the #100DaysOfCode readers and people looking for code answers.

Aside

If you have not read my previous posts I have now moved my blog to the awesome UpCloud host (signup using this link to get $25 free UpCloud VM credit). I compared Digital Ocean, Vultr and UpCloud Disk IO here and UpCloud came out on top by a long way (read the blog post here). Here is my blog post on moving from Vultr to UpCloud.

Buy a domain name here

Domain names for just 88 cents!

As promised, Java code.

Background

I am developing a Java (Windows/Mac/Linux) JavaFX app to assist me (and others) click their way through a Server deployment (domain name purchase, email setup, DNS etc) to the configuration (server host, operating, web server, database etc) to securing (DNSSEC, SPF, DMARC, Firewall etc).

I want to automate much of what I have learned over the last 2 years building apps and services (see all blog DevSecOps posts here: https://fearby.com/all/ ) on a self-managed Linux stack. I love the lower cost, higher security and flexibility of deploying self-managed servers on Linux (I love UpCloud) but not the command line interactions (that’s why I am learning Java, I do not want to develop another web-based GUI as I find them less secure than a good SSH connection). I have been developing on Windows since 1999.

Now show me Jave code.

Save date-time variables in Controller Initialize event to use in Logging

I like to log console events to a filename that is the date-time an app was started.  Add this to “public class Controller implements Initializable”

public Date todaysDateTime = new Date();
DateFormat datetimeFileNameCompatible = new SimpleDateFormat("dd-MMM-yyyy HH-mm-ss.S");
public String strLogFileTimeFilename = "zAPPDISCO - " + datetimeFileNameCompatible.format(todaysDateTime);

Now the log filename can be used below in a log function (DoLog).

Read Ini File

Download http://ini4j.sourceforge.net/ (binary files) and add ini4j-0.5.4.jar to your source folder (or use Maven etc to download the package)

Import the ini4j class to your Controller.

import org.ini4j.Ini;

Sample appname.ini file

# Ini file comment goes here

[config]
forceoffline = false
log = true

[settings]
checkipatstartup = true
checkinternetconnectionatstartup = true

[app]
name=blah blah app name
app_major = 1
appminor = 0
apprevision = 18

[mainwindow]
mainwidth = 1619.0
mainheight = 1119.0
mainleft = 147.0
maintop = 44.0

[settingswindow]
settingswidth = 1286.0
settingsheight = 1010.0
settingsleft = 9.0
settingstop = 153.0

Load an Ini file

objIni = new Ini();
System.out.println("  - Opening app.ini" );
try {
    objIni.load( new FileReader("src/appname/appname.ini"));
    System.out.println("   - Loaded INI (OK)" );

} catch (IOException ex) {
    System.out.println("   - Error Loading appname.ini ( " + ex.toString() + ")");

}

Now we are ready to load values from the loaded Ini file.

Load a Boolean from Ini file

I like to set if an app can talk to the net (by checking an Ini file to see if a user does not want online activity).

private Boolean FORCE_OFFLINE = false;
FORCE_OFFLINE = objIni.get("config","forceoffline",boolean.class);

Load String from an Ini File

System.out.println (" - App Name: " + objIni.get("app","name"));

Global Variables Class

package appname;

public class GlobalVariables {

    public int APP_MAJOR = 0;
    public int APP_MINOR = 0;
    public int APP_REVISION = 18;

    //etc
}

Copy the global variables class in a new controller, add the following code to your new controller’s “public class Controller implements Initializable” function

GlobalVariables global = new GlobalVariables();

Read the constants in the global variable class (copy)

DoLog("Started App Disco (v" + global.APP_MAJOR + "." + global.APP_MINOR  + "." + global.APP_REVISION + ") - https://fearby.com");

Log function that writes to the stdout console and physical log file if desired (set in the ini file)

private void DoLog(String logThis) { 
    // Log to std out
    System.out.println(logThis); 

    // Write to log file
    try{
    	// Declare a new Ini object
        objIni = new Ini();

        System.out.println("  - Opening appname.ini" );
        try {
            objIni.load( new FileReader("src/appname/appname.ini"));
            System.out.println("   - Loaded INI (OK)" );
        } catch (IOException ex) {
        	// Error
            System.out.println("   - Error Reading from appname.ini ( " + ex.toString() + ")");
        }

        // Check the ini file and see if the user wants to out output a log file.
        System.out.println("    - Reading [config] section in Ini file" );

        Boolean DO_LOG;
        DO_LOG = objIni.get("config","log",boolean.class);
        System.out.println("     - DO_LOG = " + DO_LOG.toString() );

        // Does the use want the console to be logged to a date stamped file too?
        if (DO_LOG == true) {
            
            // Append To File
            FileWriter fstream = new FileWriter( strLogFileTimeFilename.toString() + ".log", true);
            BufferedWriter out = new BufferedWriter(fstream);

            // Get Latest Time to prefix to the log entry
            Date todaysDateTimeLog = new Date();
            DateFormat datetimeHumanReadableFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
            String strLogFileTimeHuman = datetimeHumanReadableFormat.format(todaysDateTimeLog);

            // Log Desired Line
            String strLogThisTS = strLogFileTimeHuman.toString() + " = " +  logThis;
            out.write(strLogThisTS + "\n");

            //Close the output stream
            out.close();

        } else {
            //System.out.println("      - Skipping logging as set in the ini file.." );
        }


    } catch (Exception e){
    	//Catch exception if any
        // todo: Need to write to System.out.printl to prevent loop
        System.out.println ("Error: " + e.getMessage());  
        
    }
}

Get Contents from URL

private static String getContentsFromURL(String theUrl)
{
    StringBuilder content = new StringBuilder();

    try
    {
        // create a url object
        URL url = new URL(theUrl);

        //todo: Add Newwor check code
        
        URLConnection urlConnection = url.openConnection();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));

        String line;

        while ((line = bufferedReader.readLine()) != null)
        {
            content.append(line + "\n");
        }
        bufferedReader.close();
    }
    catch(Exception e) {
        e.printStackTrace();
    }

    return content.toString();
}

Test the internet connection by downloading the contents of a URL

String isup = getContentsFromURL("https://audit.fearby.com/isup/");
System.out.println( "Is UP: " + isup.trim().toUpperCase().toString());

Get the IPV4 address of the calling client

String isup = getContentsFromURL("https://audit.fearby.com/ip/");
System.out.println( "Is UP: " + isup.trim().toUpperCase().toString());

The IP page contains

<?php
echo htmlspecialchars($_SERVER['REMOTE_ADDR'], ENT_QUOTES, 'UTF-8');
?>

SSH to a server and run a command

This is handy for connecting to a server via SSH (and using an SSH passphrase, not a system username password). This is using the Jsch library from http://www.jcraft.com/jsch/

try {
    JSch jsch = new JSch();

    String user = "sshusername";
    DoLog("User: " + user);

    String host = "yourserver.com";
    DoLog("Host: " + host);

    int port = 22;
    DoLog("Port: " + port);

    String privateKey = System.getProperty("user.dir") + "/" +  "yourserver.rsa";
    DoLog("Private Key: " + System.getProperty("user.dir") + "/" +  "yourserver.rsa");

    String sshPassPhrase = "@dd-y0ur-really-str0ng-ssh-pa$word-h3r3";

    DoLog("Adding ssh key passphrase to session");
    jsch.addIdentity(privateKey, sshPassPhrase);
    DoLog("Private Key added to ssh session");

    Session session = jsch.getSession(user, host, port);
    DoLog("Session Created");

    java.util.Properties config = new java.util.Properties();
// see http://stackoverflow.com/questions/30178936/jsch-sftp-security-with-session-setconfigstricthostkeychecking-no

    DoLog("SSH Config: StrictHostKeyChecking: no");
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);

    DoLog("Connecting");
    session.connect();

    DoLog("Preparing Remote Command");
    String command = "uptime";

    Channel channel = session.openChannel("exec");
    ((ChannelExec)channel).setCommand(command);
    channel.setInputStream(null);
    ((ChannelExec)channel).setErrStream(System.err);

    InputStream input = channel.getInputStream();
    channel.connect();

    try {
        InputStreamReader inputReader = new InputStreamReader(input);
        BufferedReader bufferedReader = new BufferedReader(inputReader);
        String line = null;
        while((line = bufferedReader.readLine()) != null){
            System.out.println(line);
        }
        bufferedReader.close();

        inputReader.close(); }
    catch (IOException ex) {
        ex.printStackTrace();
    }
    channel.disconnect();

    session.disconnect();
    DoLog("SSH session disconnected.....");


} catch (Exception e) {
    System.err.println(e);
}

Output:

16:32:06 up 7 days, 14:59, 1 user, load average: 0.08, 0.02, 0.01

Read more on RSA keys here.

Generate an RSA key here.

Upload a file to a server via SCP over SSH

try {
    JSch jsch = new JSch();

    String user = "sshusername";
    DoLog("User: " + user);

    String host = "yourserver.com";
    DoLog("Host: " + host);

    int port = 22;
    DoLog("Port: " + port);

    String privateKey = System.getProperty("user.dir") + "/" +  "yourserver.rsa";
    DoLog("Private Key: " + System.getProperty("user.dir") + "/" +  "yourserver.rsa");

    String sshPassPhrase = "@dd-y0ur-really-str0ng-ssh-pa$word-h3r3";
    DoLog("Adding ssh key passphrase to session");
    
    jsch.addIdentity(privateKey, sshPassPhrase);
    DoLog("Private Key added to ssh session");

    Session session = jsch.getSession(user, host, port);
    DoLog("Session Created");

    java.util.Properties config = new java.util.Properties();

    //session.setConfig(
    //        "PreferredAuthentications",
    //        "publickey,gssapi-with-mic,keyboard-interactive,password");

    // disabling StrictHostKeyChecking may help to make connection but makes it insecure
    // see http://stackoverflow.com/questions/30178936/jsch-sftp-security-with-session-setconfigstricthostkeychecking-no

    DoLog("SSH Config: StrictHostKeyChecking: no");
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);

    DoLog("Connecting");
    session.connect();


    DoLog("Preparing SFTP");
    Channel channel = session.openChannel("sftp");
    channel.setInputStream(System.in);
    channel.setOutputStream(System.out);
    channel.connect();

    ChannelSftp c = (ChannelSftp) channel;
    String fileName = "upload.txt";
    DoLog("Uplaoding file: " + fileName + " to " + "/");
    c.put(fileName, "/");
    c.exit();
    DoLog("Done Uploading File");
    channel.disconnect();



} catch (Exception e) {
    System.err.println(e);
}

On the server:

cat /upload.txt
>Hello World

Encrypt Text (AES/CBC/PKCS5/SHA-256)

public static byte[] encrypt(String strInput, String strPasswordKey) throws Exception {
    System.out.println("\n\nEncrypt()");
    byte[] clean = strInput.getBytes();

    // Generating IV
    int ivSize = 16;

    byte[] iv = new byte[ivSize];
    SecureRandom strRandom = new SecureRandom();
    
    strRandom.nextBytes(iv);
    IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
    
    // Hashing key
    MessageDigest strDigest = MessageDigest.getInstance("SHA-256");
    
    strDigest.update(strPasswordKey.getBytes("UTF-8"));
    byte[] keyBytes = new byte[16];
    
    System.arraycopy(strDigest.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
    
    // Encrypt
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParamSpec);

    byte[] encrypted = cipher.doFinal(clean);
    
    // Combine IV and encrypted part
    byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];

    System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
    
    System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);

    String senctext = new String(encrypted, StandardCharsets.UTF_8);

    System.out.println("   encrypted: " + senctext.toString() + ", encryptedIVAndText: " + encryptedIVAndText.toString() + ", size: " + ivSize + ", length: " + encrypted.length);

    return encryptedIVAndText;
}

Decrypt Text (AES/CBC/PKCS5/SHA-256)

public static String decrypt(byte[] encryptedIvTextBytes, String strPasswordKey) throws Exception {
    System.out.println("\n\ndecrypt()");
    int ivSize = 16;
    int keySize = 16;

    // Extract IV
    byte[] iv = new byte[ivSize];
    System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
    IvParameterSpec ivParamSpec = new IvParameterSpec(iv);

    // Extract encrypted part
    int encryptedSize = encryptedIvTextBytes.length - ivSize;
    byte[] encryptedBytes = new byte[encryptedSize];
    System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);

    // Hash key
    byte[] keyBytes = new byte[keySize];
    MessageDigest strDigest = MessageDigest.getInstance("SHA-256");
    strDigest.update(strPasswordKey.getBytes());
    System.arraycopy(strDigest.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

    // Decrypt
    Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParamSpec);
    byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);

    return new String(decrypted);
}

Input Dialog and Display the Input text in a Dialog

// Input Dialog
TextInputDialog dialog = new TextInputDialog("Simon");
dialog.setTitle("Text Input Dialog");
dialog.setHeaderText("Look, a Text Input Dialog");
dialog.setContentText("Please enter your name:");
Optional<String> result = dialog.showAndWait();
System.out.println("Dialog Result: " + result);
Alert alertinputdialog = new Alert(AlertType.INFORMATION);
alertinputdialog.setTitle("Input Result");
alertinputdialog.setHeaderText(null);
if (result.isPresent()) {
    alertinputdialog.setContentText( "Result: " + result.get().toString());
} else {
    alertinputdialog.setContentText("Result: ");
}
alertinputdialog.showAndWait();

Input:

Java Input Box

GUI Output:

Java Dialog

Standard Message Box

// Standard Message Box
Alert alertmessagebox = new Alert(AlertType.INFORMATION);
alertmessagebox.setTitle("Base64 (Style 1/2)");
alertmessagebox.setHeaderText(null);
alertmessagebox.setContentText("About to convert '" + result.get().toString() + "' to Base64");
alertmessagebox.showAndWait();

Output:

Standard Message Box

Detailed Message Box

// Detailed Message Box
Alert alertwarning = new Alert(AlertType.WARNING);
alertwarning.setTitle("Base64 (Style 2/2)");
alertwarning.setHeaderText("About to convert '" + result.get().toString() + "' to Base64");
alertwarning.setContentText("Base64 strings can be reversed");
alertwarning.showAndWait();

GUI Output:

Detailed Java Message Box

Exception Dialog

//Exception Message Box
Alert alertexception = new Alert(AlertType.ERROR);
alertexception.setTitle("Exception Dialog");
alertexception.setHeaderText("Look, an Exception Dialog");
alertexception.setContentText("Could not find file blablah.txt!");
Exception ex = new FileNotFoundException("Could not find file blablah.txt");
// Create expandable Exception.
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
String exceptionText = sw.toString();
Label label = new Label("The exception stacktrace was:");
TextArea textArea = new TextArea(exceptionText);
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane expContent = new GridPane();
expContent.setMaxWidth(Double.MAX_VALUE);
expContent.add(label, 0, 0);
expContent.add(textArea, 0, 1);
// Set expandable Exception into the dialog pane.
alertexception.getDialogPane().setExpandableContent(expContent);
alertexception.showAndWait();

GUI Output:

Exception dialog with a label textbox, textfield and button.

Close Application

Platform.exit();
System.exit(0);

Close Child Windows

  1. Add Label to the scene (so we can get the parent scene later)
  2. Declare the label in the Controller initialize function ( “public Label lblTitle;”)
  3. Close the stage
Stage stage = (Stage) lblTitle.getScene().getWindow();
stage.close();

Handle Listview Item Select

try{
	DoLog("Selected Server: " + lvwServers.getSelectionModel().getSelectedItem().toString() );
} catch( java.lang.NullPointerException null_error ) {
	return;
}

Open URL in Browser

try {
    Desktop.getDesktop().browse(new URI("https://fearby.com"));
} catch (IOException e1) {
    e1.printStackTrace();
} catch (URISyntaxException e1) {
    e1.printStackTrace();
}

Ask for Input, Add to listview and soft the listview

// Get Parent Stage (use existing label in scene)
Stage stage = (Stage) lblTitle.getScene().getWindow();

// Input Dialog
TextInputDialog dialog = new TextInputDialog("Apple");
dialog.setTitle("Enter a Fruit");
dialog.setHeaderText("Enter a Fruit");
dialog.initOwner(stage.getScene().getWindow());
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.setResizable(Boolean.FALSE);
dialog.setContentText("e.g enter a long description here...");

Optional<String> result = dialog.showAndWait();

if (result.isPresent()) {
    System.out.println( "Fruit: " + result.get());
    lvwFruit.getItems().add(result.get());
} else {
    System.out.println("Result: ");
}

// Sory Listview
lvwFruit.getItems().sorted();

Open FXML Scene File and Modal Child Window

        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("childscene.fxml"));
            Parent root1 = (Parent) fxmlLoader.load();
            Stage stage = new Stage();
            stage.initModality(Modality.APPLICATION_MODAL);
            stage.initStyle(StageStyle.UNDECORATED);
            stage.initStyle((StageStyle.UTILITY));
            stage.setTitle("Child Scene Window Title");
            stage.setScene(new Scene(root1));
            stage.show();
        }
        catch(IOException e) {
            e.printStackTrace();
        }

Base64 Encode and Decode

// Base 64
String sString = result.get().toString();
System.out.println("String sString: " + sString);
try {
    byte[] sbString = sString.getBytes("UTF-8");
    System.out.println("Byte Array - sbString: " + sbString);

    for(byte b : sbString){
        System.out.println(b);
    }
}
catch (Exception ex2)
{
    ex2.printStackTrace();
}
String sbbase64EncodedString = Base64.getEncoder().encodeToString(sString.getBytes());
System.out.println("Base64 Encoded - base64EncodedString: " + sbbase64EncodedString);
byte[] sbbase64DecodedString = Base64.getMimeDecoder().decode(sbbase64EncodedString);
String sbase64DecodedString = new String(sbbase64DecodedString);
System.out.println("Base64 Decoded - sbase64DecodedString: " + sbase64DecodedString);

// Message Box Result of Base64
Alert alertresult = new Alert(AlertType.INFORMATION);
alertresult.setTitle("Base64");
alertresult.setHeaderText("Input String: " + sString);
alertresult.setContentText("Base64 Encoded: " + sbbase64EncodedString + "\nDecoded Base64: " + sbase64DecodedString);
alertresult.showAndWait();

CLI Output:

> Base64 Encoded – base64EncodedString: U2ltb24=
> Base64 Decoded – sbase64DecodedString: Simon

GUI Output:

Message box with base64 text

OK and Cancel Confirmation Box

// MessageBox with Buttons
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
alert.setHeaderText("Look, a Confirmation Dialog");
alert.setContentText("Are you ok with this?");

Optional<ButtonType> result2 = alert.showAndWait();
if (result2.get() == ButtonType.OK){
    System.out.println("OK Clicked");
} else {
    System.out.println("Other Clicked");
}

GUI Output:

OK Cancel Dialog Box

Confirmation Box with four options

// Messagebox with many buttons
Alert alertmessaegmanyoptions = new Alert(AlertType.CONFIRMATION);
alertmessaegmanyoptions.setTitle("Confirmation Dialog with Custom Actions");
alertmessaegmanyoptions.setHeaderText("Look, a Confirmation Dialog with Custom Actions");
alertmessaegmanyoptions.setContentText("Choose your option.");
ButtonType buttonTypeOne = new ButtonType("Ubuntu", ButtonData.HELP_2);
ButtonType buttonTypeTwo = new ButtonType("Debian");
ButtonType buttonTypeThree = new ButtonType("Windows");
ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(buttonTypeOne, buttonTypeTwo, buttonTypeThree, buttonTypeCancel);
Optional<ButtonType> result3 = alert.showAndWait();
if (result3.get() == buttonTypeOne){
    System.out.println("Ubuntu Clicked");

} else if (result3.get() == buttonTypeTwo) {
    System.out.println("Debian Clicked");

} else if (result3.get() == buttonTypeThree) {
    System.out.println("Windows Clicked");

} else if (result3.get() == buttonTypeCancel) {
    System.out.println("Cancel Clicked");

} else {
    System.out.println("Nothing Clicked");
}

GUI Output:

Confirmation box with four choices

Encrypt, Base64, AES/CBC/SHA-256 Encryption and Decrypt

fyi: Encrypt and Decrypt functions are above.

String sInputString = result.get().toString();
String sInputStringBas64 = Base64.getEncoder().encodeToString(sInputString.getBytes());
String sEncryptionKey = "pa$w1rd1";

try {
    byte[] encrypted = encrypt(sInputStringBas64, sEncryptionKey);

    String sEncryptedText = new String(encrypted, StandardCharsets.UTF_8);
    System.out.println(sEncryptedText);

    try {
        String sDecryptedText = decrypt(encrypted, sEncryptionKey);
        System.out.println("decrypted: " + sDecryptedText);

        byte[] sbbase64EncryptedDecodedString = Base64.getMimeDecoder().decode(sDecryptedText);
        String sbase64EncryptedDecodedString = new String(sbbase64EncryptedDecodedString);

        // Encryption Message Box
        Alert encryptionmessagebox = new Alert(AlertType.INFORMATION);
        encryptionmessagebox.setTitle("Encryption");
        encryptionmessagebox.setHeaderText(null);
        encryptionmessagebox.setContentText("Input String:\n" + sInputString
                        + "\n\n  Input as Base64:\n   " + sInputStringBas64
                        + "\n\n  Encryption Key:\n  " + sEncryptionKey
                        + "\n\n  Encryption Method:\n  AES/CBC/PKCS5Padding SHA-256 IV"
                        + "\n\n    Encrypted Text:\n    " + sEncryptedText
                        + "\n\n  Decrypted Text:\n  " + sDecryptedText
                        + "\n\nDecoded Base64:\n" + sbase64EncryptedDecodedString
        );
        encryptionmessagebox.showAndWait();
    }
    catch (Exception ee)
    {
        ee.printStackTrace();
    }
}
catch (Exception ex2)
    {
        ex2.printStackTrace();
    }

GUI Output:

Encrypt and decrypt

Credits 

Encryption Help: https://proandroiddev.com/security-best-practices-symmetric-encryption-with-aes-in-java-7616beaaade9

Dialogue Help: https://code.makery.ch/blog/javafx-dialogs-official/

General JavaFX Help: http://tutorials.jenkov.com/javafx/index.html

Ini File Help: Simple Java API Windows style .ini file handling. Also provide Java Preferences API
functionality on top of .ini file. https://sourceforge.net/projects/ini4j/

SSH JScH Help – JSch is a pure Java implementation of SSH2: http://www.jcraft.com/jsch/

JSch 0.0.* was released under the GNU LGPL license. Later, we have switched
over to a BSD-style license.

——————————————————————————
Copyright (c) 2002-2015 Atsuhiko Yamanaka, JCraft,Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.

3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
——————————————————————————

——————————————————————————

I hope this guide helps someone.

Please consider using my referral code and get $25 UpCloud VM credit if you need to create a server online.

https://www.upcloud.com/register/?promo=D84793

Ask a question or recommend an article

[contact-form-7 id=”30″ title=”Ask a Question”]

Revision History

v1.0 Initial Post

Filed Under: Code, Java Tagged With: code, java, jdx

Using OWASP ZAP GUI to scan your Applications for security issues

March 17, 2018 by Simon

OWASP is a non-profit that lists the Top Ten Most Critical Web Application Security Risks, they also have a GUI Java tool called OWASP Zap that you can use to check your apps for security issue.

I have a number of guides on moving hosting away form CPanel , Setting up VM’s on AWS, Vultr or Digital Ocean along with installing and managing WordPress from the command line. It is important that you always update your site and software and test your sites and software for vulnerabilities. Zap is free and completely open source.

Disclaimer, I am not an expert (this Zap post and my past Kali Linux guide will be updated as I learn more).

OWASP Top 10

OWASP has a top 10 list of things to review.

OWASP Top 10

Download the OWASP 10 10 Application security risks PDF here form here.

Using the free OWASP Zap Tool

Snip from https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project

“The OWASP Zed Attack Proxy (ZAP) is one of the world’s most popular free security tools and is actively maintained by hundreds of international volunteers*. It can help you automatically find security vulnerabilities in your web applications while you are developing and testing your applications. It’s also a great tool for experienced pentesters to use for manual security testing.”

Zap Overview

Here is a quick demo of Zap in action.

Do check out the official Zap videos on youtube: https://www.youtube.com/user/OWASPGLOBAL/videos if you want to learn more.

Installing Zap

Download Zap from here.

Download Zap

Download Options

Download

Download contents

Run Install

Copy to the app to the OSX Application folder

Installing

App Installed

App Insatalled

Open OSX’s Privacy and Security screen and click Open Anyway

Open Anwway

OWASP Zap is now Installed

Insallled

Ready for a Scan

Blind Scan

But before we do let’s check out the Options

Options

OWASP Zap allows you to label reports to ad from anyone you want.

Report Label Options

Now let’s update the program and plugins, Click Manage Add-ons

Manage Adons

Click Update All to Update addons

Updates

I clicked Update All

Plugins

Installed some plugins

Marketplace

Zap is Ready

Zap

Add a site and right click on the site and you can perform an active scan or port scan.

Right click Zap

First Scan (https failed)

https failed

I enabled unsafe SSL/TLS Renegotiation.

Allow Unsafe HTTPS

This did not work and this guide said I needed to install the “Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files” from here.

Cryptography Files OSX

The extract files to /Library/Java/JavaVirtualMachines/%your_jdk%/Contents/Home/jre/lib/security

Extract

I restarted OWASP Zap and tried to scan my site buy it appears Cloudflare (that I recently set up) was blocking my scans and reported error 403. I decided to scan another site of mine that was not on Cloudflare but had the same Lets Encrypt style SSL cert.

fyi: I own and set up the site I queried below.

Zap Results

OWASP Zap scan performed over 800 requests and tried traversal exploits and many other checks. Do repair any major failures you find.

Zan Scan

Generating a Report

To generate a report click Report then the appropriate generation menu of choice.

Generate Report

FYI: The High Priority Alert is a false positive with an HTML item being mistaken for a CC number.

I hope this guide helps someone. Happy software/server hardening and good luck.

More Reading

Check out my Kali Linux guide.

Ask a question or recommend an article

[contact-form-7 id=”30″ title=”Ask a Question”]

Revision History

V1.3 fixed hasting typo.

v1.2 False Positive

v1.1 updated main features

v1.0 Initial post

Filed Under: Cloud, Cloudflare, Code, DNS, Exploit, Firewall, LetsEncrypt, MySQL, owasp, Secure, Security, ssl, Ubuntu Tagged With: Applications, for, gui, issues, OWASP, scan, security, to, Using, your, ZAP

PHP 7 code to send object oriented sanitised input data via bound parameters to a MYSQL database

November 1, 2017 by Simon

Sanitising user input is a golden rule with web developing (see https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet ), here is my code snippet to sanitise and parameterise MySQL queries in PHP 7.0.

First, watch and follow @jawache (Asim Hussein) demo how common hacks happen and why you should update and patch software often, sanitise user data and set up a firewall.

I have blogged before on how to set up a Vultr server and configure it, How to secure Ubuntu in the Cloud, How to run an Ubuntu System Audit and Beyond SSL with Content Security Policy, Public Key Pinning etc but a 100% secure server is impossible as zero-day exploits and flaws (e.g WPA WiFi) remind us how limited technology lifespans can be. Yes, you can setup firewalls on Ubuntu and WordPress but you are only one exploit away from being hacked. Below is my code snippet (in PHP) to sanitise incoming data, query a MySQL database with object-oriented calls in PHP 7.0 and return data in variables. I have set up a firewall to block access to MySQL and non-essential ports (use https://www.shodan.io/ to test your server’s ports). I was using older deprecated PHP 5 era database calls and I researched newer calls available in PHP 7.0.

When you log in to an Ubuntu server and it says the following you should update

89 packages can be updated.
35 updates are security updates.

Also update software, node, npm etc

This code outputs too much information but will help you setup and get data on your servers (as long as you replace your database, table and field names).

<?php
echo "Last modified: " . date ("F d Y H:i:s.", getlastmod()) . "<br /><br />";
date_default_timezone_set('Australia/Sydney');

$dbhost = '127.0.0.1';
$dbusername = 'themysqlaccount';
$dbpassword = 'themysqlpassword';
$dbname = 'thedatabasename';
$con = mysqli_connect($dbhost, $dbusername, $dbpassword, $dbname);

//Debug stuff
//echo var_dump($con);
//printf(" - Error: %s.\n", $stmt->error);

if($con->connect_errno > 0){
    printf(" - Error: %s.\n", $stmt->error);
    die("Error: Unable to connect to MySQL (E001)");
} else {
 echo "Charset set to utf8<br />";
 mysqli_set_charset($con,"utf8");
}

if (!$con) {
    echo "Error: Unable to connect to MySQL (E002)" . PHP_EOL;
    echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL;
    echo "Debugging error: " . mysqli_connect_error() . PHP_EOL;
    exit;
} else {
    echo "Database Connection OK<br />";

    echo "&nbsp; Success: A proper connection to MySQL was made! The my_db database is great." . PHP_EOL . "<br />";
    echo "&nbsp; &nbsp;- Host information: " . mysqli_get_host_info($con) . PHP_EOL . "<br />";
    echo "&nbsp; &nbsp;- Server Info: '" . mysqli_get_server_info($con) . "'<br />";
    echo "&nbsp; &nbsp;- Server Protocol Info : ". mysqli_get_proto_info($con) . "<br />";
    echo "&nbsp; &nbsp;- Server Version: " . mysqli_get_server_version($con) . "<br />";
    //echo " - Server Connection Stats: " . print_r(mysqli_get_connection_stats($con)) . "<br />";
    echo "&nbsp; &nbsp;- Client Version: " . mysqli_get_client_version($con) . "<br />";
    echo "&nbsp; &nbsp;- Client Info: '" . mysqli_get_client_info() . "'<br />";

echo "Ready to Query the database '$dbname'.<br />";

// Input Var's that are parameterized/bound into the query statement
// I pre fill three vaiables with known fields in my users table
// Goot article in manual sanitization of strings in PHP http://php.net/manual/en/filter.filters.sanitize.php
    $in_username = mysqli_real_escape_string($con, 'FearTec');
    $in_f_guid = mysqli_real_escape_string($con, '5161a571-4a51-468d-9e96-6a5db5d35b1c');
    $in_mobile = mysqli_real_escape_string($con,'0456629533');

// Output Var's that the query fills after querying the database
// These variables will be filled with data from the current returned row
    $out_id = "";
    $out_f_guid = "";
    $out_username = "";
    $out_mobile = "";

echo "1. About to query the database: '$dbname'<br />";
$stmt = mysqli_stmt_init($con);
if (mysqli_stmt_prepare($stmt,"SELECT id, username, guid, user_mobile FROM thedatabasename WHERE username = ? AND guid = ? AND user_mobile = ?")) {

        echo "2. Query Returned<br />";

        /*
            Type specification chars
            Character   Description
            i   corresponding variable has type integer
            d   corresponding variable has type double
            s   corresponding variable has type string
            b   corresponding variable is a blob and will be sent in packets
        */
        mysqli_stmt_bind_param($stmt, 'sss', $in_username, $in_guid, $in_mobile);

        mysqli_stmt_execute($stmt);

        mysqli_stmt_bind_result($stmt, $out_id, $out_username, $out_guid, $out_mobile);

        mysqli_stmt_fetch($stmt);

        // Do something with the 1st returned row        
        echo " - Row: ID: $out_id, GUID: $out_guid, USR: $out_username, MOB: $out_mobile";//
        // Do we have more rows to process
        while($stmt->fetch()) { 
                // Deal with other rows
                echo " - Row: ID: $out_id, GUID: $out_f_guid, USR: $out_username, MOB: $out_mobile<br />";
        }
        mysqli_stmt_close($stmt);
        
        echo "c<br />";
    }
     else {
        echo "3. Error Querying<br/>";
        printf(" - Error: %s.\n", $stmt->error);
    }

}    

?>

Returned Data

Last modified: November 01 2017 16:43:01.
Charset set to utf8
Database Connection OK
  Success: A proper connection to MySQL was made! The my_db database is great. 
   - Host information: 127.0.0.1 via TCP/IP 
   - Server Info: '5.7.19-0ubuntu0.16.04.1'
   - Server Protocol Info : 10
   - Server Version: 50719
   - Client Version: 50012
   - Client Info: 'mysqlnd 5.0.12-dev - 20150407 - $Id: b5########################

Variable Bind Parameter Types

When you bind an incoming variable you can inform MySQL what the data type is expected to be.

mysqli_stmt_bind_param: Type specification chars
Character   Description
i   corresponding variable has type integer
d   corresponding variable has type double
s   corresponding variable has type string
b   corresponding variable is a blob and will be sent in packets

Debug Options

Errors Enabled: Turn on PHP Debug Errors On

Turning on errors on production servers is bad but on development.

First, find php.ini files

locate php.ini
/php.ini.bak
/.c9/metadata/workspace/etc/php/7.0/fpm/php.ini
/etc/php/7.0/apache2/php.ini
/etc/php/7.0/cli/php.ini
/etc/php/7.0/fpm/php.ini
/etc/php/7.0/phpdbg/php.ini
/usr/lib/php/7.0/php.ini-development
/usr/lib/php/7.0/php.ini-production
/usr/lib/php/7.0/php.ini-production.cli

Edit your appropriate PHP file

sudo nano /etc/php/7.0/fpm/php.ini

And turn on Error reporting.

Restart PHP and NGINX

sudo /etc/init.d/php7.0-fpm restart
sudo /etc/init.d/nginx restart

If you need to view your active php.ini file or see PHP configuration settings, add this to a .php file on your web server and view its contents.

<?php
phpinfo()
?>

It is amazing how clear errors can be

PHP Error

Dump Connection Vars: PHP mysqli_connect: var_dump($con)

echo var_dump($con);

Output:

public 'affected_rows' => int 0
  public 'client_info' => string 'mysqlnd 5.0.12-dev - 20150407 - $Id: b5###############################3

Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.

echo "&nbsp; Success: Database connection OK." . PHP_EOL . "<br />";
echo "&nbsp; &nbsp;- Host information: " . mysqli_get_host_info($con) . PHP_EOL . "<br />";
echo "&nbsp; &nbsp;- Server Info: '" . mysqli_get_server_info($con) . "'<br />";
echo "&nbsp; &nbsp;- Server Protocol Info : ". mysqli_get_proto_info($con) . "<br />";
echo "&nbsp; &nbsp;- Server Version: " . mysqli_get_server_version($con) . "<br />";
//echo " - Server Connection Stats: " . print_r(mysqli_get_connection_stats($con)) . "<br />";
echo "&nbsp; &nbsp;- Client Version: " . mysqli_get_client_version($con) . "<br />";
echo "&nbsp; &nbsp;- Client Info: '" . mysqli_get_client_info() . "'<br />";

Output:

Success: Database connection OK. 
   - Host information: 127.0.0.1 via TCP/IP 
   - Server Info: '5.7.19-0ubuntu0.16.04.1'
   - Server Protocol Info : 10
   - Server Version: 50719
   - Client Version: 50012
   - Client Info: 'mysqlnd 5.0.12-dev - 20150407 - $Id: b5########################################

Show errors in failed if  statements: mysqli_stmt_prepare else

printf(" - Error: %s.\n", $stmt->error);

Output:

Error: Table 'thedatabasename.invalidtablename' doesn't exist.

Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

Ready to Query the database 'thedatabasename'. 1. About to query the database: 'thedatabasename' 2. Query Returned - Row: ID: 1, GUID: 0000000-0000-0000-0000-000000000001, USR: Bob, MOB: 1234567890 - Row: ID: 2, GUID: 0000000-0000-0000-0000-000000000002, USR: Joe, MOB: 1234567891 - Row: ID: 3, GUID: 0000000-0000-0000-0000-000000000003, USR: Jane, MOB: 1234567892

Variable Bind Parameter Types

When you bind an incoming variable you can inform MySQL what the data type is expected to be.


Debug Options

Errors Enabled: Turn on PHP Debug Errors On

Turning on errors on production servers is bad but on on development.

First, find php.ini files


Edit your appropriate PHP file


And turn on Error reporting.

Restart PHP and NGINX


If you need to view your active php.ini file or see php configuration settings, add this to a .php file on your web server and view it’s contents.


It is amazing how clear errors can be

PHP Error

Dump Connection Vars: PHP mysqli_connect: var_dump($con)


Output:


Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.


Output:


Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

(length=79) public 'client_version' => int 50012 public 'connect_errno' => int 0 public 'connect_error' => null public 'errno' => int 0 public 'error' => string '' (length=0) public 'error_list' => array (size=0) empty public 'field_count' => int 0 public 'host_info' => string '127.0.0.1 via TCP/IP' (length=20) public 'info' => null public 'insert_id' => int 0 public 'server_info' => string '5.7.19-0ubuntu0.16.04.1' (length=23) public 'server_version' => int 50719 public 'stat' => string 'Uptime: 1828089 Threads: 1 Questions: 15702 Slow queries: 0 Opens: 1529 Flush tables: 1 Open tables: 1461 Queries per second avg: 0.008' (length=142) public 'sqlstate' => string '00000' (length=5) public 'protocol_version' => int 10 public 'thread_id' => int 7367 public 'warning_count' => int 0

Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.


Output:


Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

Ready to Query the database 'thedatabasename'. 1. About to query the database: 'thedatabasename' 2. Query Returned - Row: ID: 1, GUID: 0000000-0000-0000-0000-000000000001, USR: Bob, MOB: 1234567890 - Row: ID: 2, GUID: 0000000-0000-0000-0000-000000000002, USR: Joe, MOB: 1234567891 - Row: ID: 3, GUID: 0000000-0000-0000-0000-000000000003, USR: Jane, MOB: 1234567892

Variable Bind Parameter Types

When you bind an incoming variable you can inform MySQL what the data type is expected to be.


Debug Options

Errors Enabled: Turn on PHP Debug Errors On

Turning on errors on production servers is bad but on on development.

First, find php.ini files


Edit your appropriate PHP file


And turn on Error reporting.

Restart PHP and NGINX


If you need to view your active php.ini file or see php configuration settings, add this to a .php file on your web server and view it’s contents.


It is amazing how clear errors can be

PHP Error

Dump Connection Vars: PHP mysqli_connect: var_dump($con)


Output:


Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.


Output:


Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

Ready to Query the database ‘thedatabasename’. 1. About to query the database: ‘thedatabasename’ 2. Query Returned – Row: ID: 1, GUID: 0000000-0000-0000-0000-000000000001, USR: Bob, MOB: 1234567890 – Row: ID: 2, GUID: 0000000-0000-0000-0000-000000000002, USR: Joe, MOB: 1234567891 – Row: ID: 3, GUID: 0000000-0000-0000-0000-000000000003, USR: Jane, MOB: 1234567892

Variable Bind Parameter Types

When you bind an incoming variable you can inform MySQL what the data type is expected to be.


Debug Options

Errors Enabled: Turn on PHP Debug Errors On

Turning on errors on production servers is bad but on on development.

First, find php.ini files


Edit your appropriate PHP file


And turn on Error reporting.

Restart PHP and NGINX


If you need to view your active php.ini file or see php configuration settings, add this to a .php file on your web server and view it’s contents.


It is amazing how clear errors can be

PHP Error

Dump Connection Vars: PHP mysqli_connect: var_dump($con)


Output:


Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.


Output:


Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

(length=79) public ‘client_version’ => int 50012 public ‘connect_errno’ => int 0 public ‘connect_error’ => null public ‘errno’ => int 0 public ‘error’ => string ” (length=0) public ‘error_list’ => array (size=0) empty public ‘field_count’ => int 0 public ‘host_info’ => string ‘127.0.0.1 via TCP/IP’ (length=20) public ‘info’ => null public ‘insert_id’ => int 0 public ‘server_info’ => string ‘5.7.19-0ubuntu0.16.04.1’ (length=23) public ‘server_version’ => int 50719 public ‘stat’ => string ‘Uptime: 1828089 Threads: 1 Questions: 15702 Slow queries: 0 Opens: 1529 Flush tables: 1 Open tables: 1461 Queries per second avg: 0.008’ (length=142) public ‘sqlstate’ => string ‘00000’ (length=5) public ‘protocol_version’ => int 10 public ‘thread_id’ => int 7367 public ‘warning_count’ => int 0

Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.


Output:


Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

Ready to Query the database ‘thedatabasename’. 1. About to query the database: ‘thedatabasename’ 2. Query Returned – Row: ID: 1, GUID: 0000000-0000-0000-0000-000000000001, USR: Bob, MOB: 1234567890 – Row: ID: 2, GUID: 0000000-0000-0000-0000-000000000002, USR: Joe, MOB: 1234567891 – Row: ID: 3, GUID: 0000000-0000-0000-0000-000000000003, USR: Jane, MOB: 1234567892

Variable Bind Parameter Types

When you bind an incoming variable you can inform MySQL what the data type is expected to be.


Debug Options

Errors Enabled: Turn on PHP Debug Errors On

Turning on errors on production servers is bad but on on development.

First, find php.ini files


Edit your appropriate PHP file


And turn on Error reporting.

Restart PHP and NGINX


If you need to view your active php.ini file or see php configuration settings, add this to a .php file on your web server and view it’s contents.


It is amazing how clear errors can be

PHP Error

Dump Connection Vars: PHP mysqli_connect: var_dump($con)


Output:


Show Environment Vars: mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_version, mysqli_get_client_version and mysqli_get_client_info.


Output:


Show errors in failed if  statements: mysqli_stmt_prepare else


Output:


Debugging is your friend.

More to come..

Donate and make this blog better


Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]

V 1.0 initial post

Short (Article):

Filed Under: Code, PHP, Security, Tech Advice, Ubuntu Tagged With: a, and, bound, code, data, database, MySQL, object, oriented, parameters, PHP 7, sanitise, send, to

Primary Sidebar

Poll

What would you like to see more posts about?
Results

Support this Blog

Create your own server today (support me by using these links

Create your own server on UpCloud here ($25 free credit).

Create your own server on Vultr here.

Create your own server on Digital Ocean here ($10 free credit).

Remember you can install the Runcloud server management dashboard here if you need DevOps help.

Advertisement:

Tags

2FA (9) Advice (17) Analytics (9) App (9) Apple (10) AWS (9) Backup (21) Business (8) CDN (8) Cloud (49) Cloudflare (8) Code (8) Development (26) Digital Ocean (13) DNS (11) Domain (27) Firewall (12) Git (7) Hosting (18) HTTPS (6) IoT (9) LetsEncrypt (7) Linux (20) Marketing (11) MySQL (24) NGINX (11) NodeJS (11) OS (10) PHP (13) Scalability (12) Scalable (14) Security (44) SEO (7) Server (26) Software (7) SSH (7) ssl (17) Tech Advice (9) Ubuntu (39) Uncategorized (23) UpCloud (12) VM (44) Vultr (24) Website (14) Wordpress (25)

Disclaimer

Terms And Conditions Of Use All content provided on this "www.fearby.com" blog is for informational purposes only. Views are his own and not his employers. The owner of this blog makes no representations as to the accuracy or completeness of any information on this site or found by following any link on this site. Never make changes to a live site without backing it up first.

Advertisement:

Footer

Popular

  • Backing up your computer automatically with BackBlaze software (no data limit)
  • How to back up an iPhone (including photos and videos) multiple ways
  • Add two factor auth login protection to WordPress with YubiCo hardware YubiKeys and or 2FA Authenticator App
  • Setup two factor authenticator protection at login on Ubuntu or Debian
  • Using the Yubico YubiKey NEO hardware-based two-factor authentication device to improve authentication and logins to OSX and software
  • I moved my domain to UpCloud (on the other side of the world) from Vultr (Sydney) and could not be happier with the performance.
  • Monitor server performance with NixStats and receive alerts by SMS, Push, Email, Telegram etc
  • Speeding up WordPress with the ewww.io ExactDN CDN and Image Compression Plugin
  • Add Google AdWords to your WordPress blog

Security

  • Check the compatibility of your WordPress theme and plugin code with PHP Compatibility Checker
  • Add two factor auth login protection to WordPress with YubiCo hardware YubiKeys and or 2FA Authenticator App
  • Setup two factor authenticator protection at login on Ubuntu or Debian
  • Using the Yubico YubiKey NEO hardware-based two-factor authentication device to improve authentication and logins to OSX and software
  • Setting up DNSSEC on a Namecheap domain hosted on UpCloud using CloudFlare
  • Set up Feature-Policy, Referrer-Policy and Content Security Policy headers in Nginx
  • Securing Google G Suite email by setting up SPF, DKIM and DMARC with Cloudflare
  • Enabling TLS 1.3 SSL on a NGINX Website (Ubuntu 16.04 server) that is using Cloudflare
  • Using the Qualys FreeScan Scanner to test your website for online vulnerabilities
  • Beyond SSL with Content Security Policy, Public Key Pinning etc
  • Upgraded to Wordfence Premium to get real-time login defence, malware scanner and two-factor authentication for WordPress logins
  • Run an Ubuntu VM system audit with Lynis
  • Securing Ubuntu in the cloud
  • No matter what server-provider you are using I strongly recommend you have a hot spare ready on a different provider

Code

  • How to code PHP on your localhost and deploy to the cloud via SFTP with PHPStorm by Jet Brains
  • Useful Java FX Code I use in a project using IntelliJ IDEA and jdk1.8.0_161.jdk
  • No matter what server-provider you are using I strongly recommend you have a hot spare ready on a different provider
  • How to setup PHP FPM on demand child workers in PHP 7.x to increase website traffic
  • Installing Android Studio 3 and creating your first Kotlin Android App
  • PHP 7 code to send object oriented sanitised input data via bound parameters to a MYSQL database
  • How to use Sublime Text editor locally to edit code files on a remote server via SSH
  • Creating your first Java FX app and using the Gluon Scene Builder in the IntelliJ IDEA IDE
  • Deploying nodejs apps in the background and monitoring them with PM2 from keymetrics.io

Tech

  • Backing up your computer automatically with BackBlaze software (no data limit)
  • How to back up an iPhone (including photos and videos) multiple ways
  • US v Huawei: The battle for 5G
  • Check the compatibility of your WordPress theme and plugin code with PHP Compatibility Checker
  • Is OSX Mojave on a 2014 MacBook Pro slower or faster than High Sierra
  • Telstra promised Fibre to the house (FTTP) when I had FTTN and this is what happened..
  • The case of the overheating Mac Book Pro and Occam’s Razor
  • Useful Linux Terminal Commands
  • Useful OSX Terminal Commands
  • Useful Linux Terminal Commands
  • What is the difference between 2D, 3D, 360 Video, AR, AR2D, AR3D, MR, VR and HR?
  • Application scalability on a budget (my journey)
  • Monitor server performance with NixStats and receive alerts by SMS, Push, Email, Telegram etc
  • Why I will never buy a new Apple Laptop until they fix the hardware cooling issues.

Wordpress

  • Replacing Google Analytics with Piwik/Matomo for a locally hosted privacy focused open source analytics solution
  • Setting web push notifications in WordPress with OneSignal
  • Telstra promised Fibre to the house (FTTP) when I had FTTN and this is what happened..
  • Check the compatibility of your WordPress theme and plugin code with PHP Compatibility Checker
  • Add two factor auth login protection to WordPress with YubiCo hardware YubiKeys and or 2FA Authenticator App
  • Monitor server performance with NixStats and receive alerts by SMS, Push, Email, Telegram etc
  • Upgraded to Wordfence Premium to get real-time login defence, malware scanner and two-factor authentication for WordPress logins
  • Wordfence Security Plugin for WordPress
  • Speeding up WordPress with the ewww.io ExactDN CDN and Image Compression Plugin
  • Installing and managing WordPress with WP-CLI from the command line on Ubuntu
  • Moving WordPress to a new self managed server away from CPanel
  • Moving WordPress to a new self managed server away from CPanel

General

  • Backing up your computer automatically with BackBlaze software (no data limit)
  • How to back up an iPhone (including photos and videos) multiple ways
  • US v Huawei: The battle for 5G
  • Using the WinSCP Client on Windows to transfer files to and from a Linux server over SFTP
  • Connecting to a server via SSH with Putty
  • Setting web push notifications in WordPress with OneSignal
  • Infographic: So you have an idea for an app
  • Restoring lost files on a Windows FAT, FAT32, NTFS or Linux EXT, Linux XFS volume with iRecover from diydatarecovery.nl
  • Building faster web apps with google tools and exceed user expectations
  • Why I will never buy a new Apple Laptop until they fix the hardware cooling issues.
  • Telstra promised Fibre to the house (FTTP) when I had FTTN and this is what happened..

Copyright © 2023 · News Pro on Genesis Framework · WordPress · Log in

Some ads on this site use cookies. You can opt-out if of local analytics tracking by scrolling to the bottom of the front page or any article and clicking "You are not opted out. Click here to opt out.". Accept Reject Read More
GDPR, Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT