Tuesday, 30 July 2019

Installing MySQL on the Raspberry Pi - part 3: Connecting from .Net

Installing the Connector

Visual Studio is not supplied with a default MySQL/MariaDB connector.
Use the MySQL connector.
https://dev.mysql.com/doc/connector-net/en/connector-net-installation.html
Run the installer.
 image
Select Typical installation
 image
In Visual Studio, to add the connector go to the Project/Add Reference. Select Assemblies and search for MySQL. Remember you will need to do this for each project (even within a solution).
 image
Tick MySQL.Data and click on OK.

Example program in VB.Net

The program uses a simple form.
One vertical Split Container, with one button in one panel, and a multi-line, docked text box with vertical scroll bar in the other panel.

Code

Public Class Form1
    ' *** Test application - 
    ' *** to a remote MariDB database, insert a row and then display all rows
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim myDB As New MySql.Data.MySqlClient.MySqlConnection("Server=192.168.1.191;Database=datastorage;Uid=datawriter;Pwd=*******;")
        Dim myCommand As New MySql.Data.MySqlClient.MySqlCommand()
        Dim myReader As MySql.Data.MySqlClient.MySqlDataReader
        Dim sSQL As String
        addtext("Connecting")
        myDB.Open()
        addtext("Connected")

        addtext("Inserting")

        sSQL = "insert into datavalues(user,title,value) values(CURRENT_USER(),'VBtest',23);"

        With myCommand
            .Connection = myDB
            .CommandText = sSQL
            .ExecuteNonQuery()
        End With
        addtext("Inserted")


        sSQL = "SELECT * FROM datavalues"
        addtext("Selecting")

        With myCommand
            .CommandText = sSQL
            myReader = .ExecuteReader()
        End With
        addtext("Selected")

        addtext("Reading")

        While myReader.Read()
            Dim sLine As String = ""
            For ix As Integer = 0 To myReader.FieldCount - 1
                If sLine <> "" Then
                    sLine = sLine & ", " & myReader.GetString(ix)
                Else
                    sLine = myReader.GetString(ix)
                End If
            Next
            addtext(sLine)
        End While
        addtext("Reading")
        addtext("Closing")
        myReader.Close()
        myDB.Close()
        addtext("Closed")
    End Sub
    ''' <summary>
    ''' Add string parameter to current content of text box
    ''' </summary>
    ''' <param name="aString">Text to be added to text box </param>
    Private Sub addtext(aString As String)
        TextBox1.Text = TextBox1.Text & aString & vbCrLf
    End Sub
End Class

Output

Connecting
Connected
Inserting
Inserted
Selecting
Selected
Reading
1, root@localhost, test, 1, 27/02/2019 11:06:09
2, root@localhost, test, 2, 27/02/2019 11:06:16
3, root@localhost, test, 3, 27/02/2019 11:06:23
5, datawriter@192.168.1.%, test, 30, 28/02/2019 13:13:07
6, datawriter@192.168.1.%, test, 30, 28/02/2019 13:13:23
7, datawriter@192.168.1.%, test, 30, 30/07/2019 08:06:21
8, datawriter@192.168.1.%, VBtest, 23, 30/07/2019 10:49:39
9, datawriter@192.168.1.%, VBtest, 23, 30/07/2019 10:58:02
Reading
Closing
Closed

Example Code in C#

This is a console application.

Code

using System;

using MySql.Data.MySqlClient;

public class MySQLTest
{
    public static void Main()
    {
        string connStr = "Server=192.168.1.191;Database=datastorage;Uid=datawriter;Pwd=********;";
        MySqlConnection myDB = new MySqlConnection(connStr);
        try
        {
            Console.WriteLine("Connecting");
            myDB.Open();
            Console.WriteLine("Connected");
            Console.WriteLine("Inserting");

            string sql = "insert into datavalues(user,title,value) values(CURRENT_USER(),'C#test',54);";
            MySqlCommand myCommand = new MySqlCommand(sql, myDB);

            myCommand.ExecuteNonQuery();
            Console.WriteLine("Inserted");

            Console.WriteLine("Selecting");
            sql = "SELECT * FROM datavalues";
            myCommand.CommandText = sql;

            MySqlDataReader myReader = myCommand.ExecuteReader();
            Console.WriteLine("Selected");

            Console.WriteLine("Reading");

            while (myReader.Read())
            {
                string rowtext = "";
                for (int ix = 0; ix < myReader.FieldCount; ix += 1)
                {
                    if (rowtext == "")
                    {
                        rowtext = string.Concat("", myReader[ix]);
                    }
                    else
                    {
                        rowtext = string.Concat(rowtext,", ", myReader[ix]);
                    }
                }
                    Console.WriteLine(rowtext);              
            }
            myReader.Close();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        myDB.Close();
        Console.WriteLine("Done.");
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}

Output

Connecting
Connected
Inserting
Inserted
Selecting
Selected
Reading
1, root@localhost, test, 1, 27/02/2019 11:06:09
2, root@localhost, test, 2, 27/02/2019 11:06:16
3, root@localhost, test, 3, 27/02/2019 11:06:23
5, datawriter@192.168.1.%, test, 30, 28/02/2019 13:13:07
6, datawriter@192.168.1.%, test, 30, 28/02/2019 13:13:23
7, datawriter@192.168.1.%, test, 30, 30/07/2019 08:06:21
8, datawriter@192.168.1.%, VBtest, 23, 30/07/2019 10:49:39
9, datawriter@192.168.1.%, VBtest, 23, 30/07/2019 10:58:02
10, datawriter@192.168.1.%, test, 30, 30/07/2019 13:28:56
11, datawriter@192.168.1.%, C#test, 54, 30/07/2019 13:42:00
12, datawriter@192.168.1.%, test, 30, 30/07/2019 13:43:13
13, datawriter@192.168.1.%, C#test, 54, 30/07/2019 13:45:37
14, datawriter@192.168.1.%, C#test, 54, 30/07/2019 13:47:51
15, datawriter@192.168.1.%, C#test, 54, 30/07/2019 13:48:04
16, datawriter@192.168.1.%, C#test, 54, 30/07/2019 13:52:03
17, datawriter@192.168.1.%, C#test, 54, 30/07/2019 13:56:07
Done.
Press any key to exit.

Wednesday, 24 July 2019

GoPro Wifi connection - part one

Background

The GoPro series of cameras have become synonymous with action cameras in general. Earlier versions have had a WiFi backpack, later versions have the WiFi option built in.

I have an elderly GoPro Hero2, that has survived three leaks - thankfully all in fresh water.


They are rust marks on the shutter button and surroundings.


Unfortunately, the only official way of connecting to a GoPro is either via their Android application, or via their PC or Mac applications. If you are using older hardware, or Linux based operating systems, there appears to be no official connection.
However, a search of the internet found the first referenced article. Once the IP address was discovered, it was a lot easier to find the other references, and more importantly the GoProWifiHack on GitHub.

Connecting to the GoPro webserver

If the GoPro has an external WiFi backpack, connect it to the back of the GoPro.

It is worth plugging in the power to the backpack, as you might spend more time on it than you expect.

Switch on the WiFi. The Wifi device name should appear on the list of available networks on your computer.

Now my GoPro Hero 2 had been set up previously, so I was able to select the connection, enter the password and connect to the device.

Now the key piece of information is the availability of a web interface.

This is located at 10.5.5.9:8080. From there you can access the videos and stills on the device.


Next - sending commands.

References

http://aikiwolfie.blogspot.com/2014/12/ubuntu-tip-connecting-to-gopro-hero4.html
https://github.com/KonradIT/goprowifihack
https://github.com/KonradIT/goprowifihack/blob/master/HERO2/README.md
https://github.com/KonradIT/goprowifihack/blob/master/HERO2/WifiCommands.md
https://github.com/KonradIT/goprowifihack/blob/master/HERO2/Mediabrowsing.md



Tuesday, 25 June 2019

Installing MySQL on the Raspberry Pi - part 3: the outside world

Connecting to the outside world

Opening the database to the outside world

The default setup of MySQL/MariaDB will only accept connections from the machine hosting the database. This is okay if your requirements only require one machine, but in most cases the database server will be accessed by other machines. One of the joys of the Raspberry Pi is that you can use them for one task, such as a central database server and then use other machines (such as other Raspberry Pis) to feed it.

You can change this default behaviour by setting a variable in one of the database's configuration files.

On a Linux machine (like a Raspberry Pi) it is located here: /etc/mysql/my.cnf

The required variable is called the bind-address. It is only relevant to the database server and not client applications running on the server. If it is visible to a client application you will get an error:

mysql: unknown variable 'bind-address=[ip]'

To add this bind address type:
sudo nano /etc/mysql/my.cnf

Look through the file, if there is an existing entry of:
bind-address = 127.0.0.1
Comment this out by putting a # symbol in front of it.
#bind-address = 127.0.0.1

Check if there is a section marked [server].
If there is no[server] entry, at the bottom of the file add the section:
[server]
Then add
bind-address = 0.0.0.0
This part of the file will look like:
[client-server]

# Import all .cnf files from configuration directory
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/

#bind-address = 127.0.0.1

[server]
bind-address = 0.0.0.0

This will allow access from other machines.

You will need to restart the server:
sudo service  mysql restart
Note: If the host machine has any firewall settings active, you may need to open the MySQL port number 3306.

Adding external users

First check what users you have set up.

Log in to the database server locally:
sudo mysql -uroot -p
And enter your database password.

To check the current users, type:
SELECT User, Host FROM mysql.user;

+-------------+-------------+
| User        | Host        |
+-------------+-------------+
| datareader  | %           |
| localreader | localhost   |
| root        | localhost   |
+-------------+-------------+

If you have followed the instructions so far, you should have something similar.

If not, set the default database to be datastorage and a data reader user:
create user 'datareader'@'%' identified by '<data reader password>';
grant select on datastorage.* to'datareader';

Connect to the database using Python

The first task is to install the connector on the machine.

Pip (and Pip3) are installers similar to the APT repository installers on Debian derived Linux but specifically for Python 2 and Python 3. Some installations use pip for Python 3, but the majority use pip for Python 2 and pip3 for Python 3. If you have used pip and your Python program cannot find something, try pip3.
From the comand line on the machine to be used:
pip3 install mysql-connector-python

This will install the required connectors to access MySQL

Test Program

import mysql.connector
print("Test database reader")
cnx = mysql.connector.connect(host="<ip address>"
                     user="datareader",
                     passwd="<password>",
                     port = 3306,
                     db="datastorage")
print("Connected")
mycursor=cnx.cursor()
sql="SELECT * FROM datavalues"
mycursor.execute(sql)
for row in mycursor.fetchall():
    result=""
    for field in row:
        result+=", " +str(field)
    print(result)
cnx.close()
The program first imports the connector.
import mysql.connector
It then creates the connection with the supplied parameters (database server address, user name, password, port number, database).
cnx = mysql.connector.connect(host="<ip address>"
                     user="datareader",
                     passwd="<password>",
                     port = 3306,
                     db="datastorage")
It then creates a cursor on that connection.
mycursor=cnx.cursor()
Executes a SQL statement using that cursor
sql="SELECT * FROM datavalues"
mycursor.execute(sql)
Prints the returned data.
for row in mycursor.fetchall():
    result=""
    for field in row:
        result+=", " +str(field)
    print(result)
And finally closes the connection.
cnx.close()
This is an example of the output:

Test database reader
Connected
, 1, root@localhost, test, 1.0, 2019-02-27 11:06:09
, 2, root@localhost, test, 2.0, 2019-02-27 11:06:16
, 3, root@localhost, test, 3.0, 2019-02-27 11:06:23

References

Tuesday, 21 May 2019

Installing MySQL on the Raspberry Pi - part 2

So, having worked through part one, you should have a working installation of MySQL.

If not, go back through and check that all of the steps have been completed.

Stored Procedures

This is a simple stored procedure to list the users in the datavalues table (remember you will need to have selected the required database using the use datastorage command).

MySQL needs to differentiate between line delimiters within the stored procedure and within the command that creates the stored procedure. The delimiter needs to be changed to differentiate between the end of line within the procedure and the end of the definition. Remember to change the delimiter back.
DELIMITER //
CREATE PROCEDURE listusers()
BEGIN
SELECT DISTINCT user from datavalues;
END//
DELIMITER ;

Use SHOW PROCEDURE STATUS; to view stored procedure names.
Use SHOW CREATE PROCEDURE <procedure name> to view the procedures.

Stored Procedure with input parameter

This is a slightly more complicated procedure which takes a username as a parameter.

DELIMITER //
CREATE PROCEDURE list_values_for_user(IN username VARCHAR(50))
BEGIN
SELECT id,value,title,created FROM datavalues WHERE user=username;
END //
DELIMITER ;

Test with:
CALL list_values_for_user('root@localhost')
MariaDB [datastorage]> call list_values_for_user('root@localhost');
+----+-------+-------+---------------------+
| id | value | title | created             |
+----+-------+-------+---------------------+
|  1 |     1 | test  | 2019-02-27 11:06:09 |
|  2 |     2 | test  | 2019-02-27 11:06:16 |
|  3 |     3 | test  | 2019-02-27 11:06:23 |
+----+-------+-------+---------------------+
3 rows in set (0.00 sec)





Wednesday, 15 May 2019

Using the built-in camera with Raspbian and OpenCV

I have an elderly Samsung Netbook which is running Raspbian Stretch as a LiveUSB.

The netbook has a built in camera, and I thought I would follow up the post on using a Raspberry Pi and a Webcam with one on the Netbook.

Installation

Follow the instructions from the previous post.

Taking a photograph

Open up a Python editor (I used IDLE 3).
Create a new file.
Copy and paste the code from the previous post.
Save the program to your usual directory).
Run the program.

Footnote

It also was a convenient check that the previous post worked on a fresh install. The post required a slight edit as the PIP3 command needed to be run under SUDO.

USB Webcam using a Raspberry Pi and Python - test

Introduction

USB webcams are very cheap, and in many cases you may already own one. Though the Official Raspberry Pi Camera is often far superior (many "High Resolution" webcams are 'Nineties era VGA resolution - 640x480), the fact that webcams are cheap and cased can make them very useful for some projects.

This posting covers the simplest of Python programs to take a photograph using the OpenCV library.

Installation

Install OpenCV

sudo apt-get install python-opencv libopencv-dev

You might find it is already installed.

Install Python bindings

Remember that pip probably installs for Python 2.x, so you will need to use pip3.

sudo pip3 install opencv-python

Please note that if you forget the sudo, you do not get an error, but it also does not work (you get an error "ImportError: No module named 'cv2'").

Taking a photograph

The following Python code takes a photograph and saves it to a file in the (pi) user's home directory.

The program takes a number of frames to allow the camera and its software to determine the best settings for exposure etc.

# Test USB web cam with OpenCV

# Imports
import cv2

# Set camera to be the default webcam
camera_port=0

# Set warm up number of frames
skip_frames=7

# Destination file
file="/home/pi/image.jpg"

# Set up camera properties
camera=cv2.VideoCapture(camera_port)
camera.set(cv2.CAP_PROP_FRAME_WIDTH,640) 
camera.set(cv2.CAP_PROP_FRAME_HEIGHT,480)

# Function to get image
def get_image():
    retval,im=camera.read()
    return im

# Test USB web cam
print("Starting photograph")

# Skip frames to allow camera to settle down
for skipping in range(skip_frames):
    temp=get_image()
print("Taking photograph")

camera_capture=get_image()

# Write image to file
cv2.imwrite(file,camera_capture)

# Remove camera object - ensures release of resources
del(camera)

print("Done")



Installing MySQL on the Raspberry Pi - part 1

Introduction

MySQL is a Free and Open Source relational database owned by Oracle Corporation. Due to concerns about the future of MySQL, MySQL was forked as a community developed version called MariaDB.

MariaDB is intended to be a drop in replacement for MySQL and is increasingly being chosen as the default "MySQL" installation on Linux distributions. Debian, the upstream Linux version for Raspbian changed to use MariaDB recently, hence the references to MariaDB in the installation text.

There are many excellent examples of MySQL installation tutorials on the web, this is just one (how useful you find it is up to you). See the references section for more information and some examples.

Set Up

Update Raspbian installation

This is the standard update/upgrade process to ensure that the Raspberry Pi has the most up to date versions of all installed software before adding new software.

sudo apt-get update
sudo apt-get upgrade

Install MySQL from repository

MySQL is available from the Raspbian repository.

sudo apt-get install mysql-server

Setup and securing the database

Run the secure installation script:
sudo mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): 
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] y
New password: 
Re-enter new password: 
Password updated successfully!
Reloading privilege tables..
 ... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] Y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
 ... Success!
Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

That is the database set up.


First connection

From the command line.
sudo mysql -uroot -p
Enter the root password.

Once you are logged in, enter the following to create a database.
create database datastorage;
The ending semi-colon is the effective end of line for a command.
grant all privileges on datastorage.* TO 'root'@'localhost' IDENTIFIED BY '<root password>';

Create a local host data reader. This user can only access the database on the server itself.
create user 'localreader'@'localhost' identified by '<user password>'
grant select on datastorage.* to'localreader'@'localhost';

This user is allowed to access the database from anywhere, but only has select access.
create user 'datareader'@'%' identified by '<user password>;
grant select on datastorage.* to'datareader'@'%';

Subsequent Connections

Logging in follows the same process a s before, from the command line.
sudo mysql -uroot -p
Enter the root password

The console does not default to a specific database, so it is best to remember to set the current database (in this case datastorage created earlier).
MariaDB [(none)]> use datastorage
Database changed
MariaDB [datastorage]>

Creating tables

This example table is to record data sent from other machines, by other users.
The table has a primary key (id) which is an integer and auto increments. The created field is a DATETIME and defaults to the current time.

CREATE TABLE datavalues(
id INT NOT NULL AUTO_INCREMENT,
user VARCHAR(50) NOT NULL ,
title VARCHAR(20) NOT NULL,
value FLOAT NOT NULL,
created DATETIME NOT NULL DEFAULT NOW(),
PRIMARY KEY(id)
);

Populating the table

From the MySQL command line:
insert into datavalues(user,title,value)
values(CURRENT_USER(),'test',1);

Test the insert:
SELECT * FROM datavalues;

References