Skip navigation
1 2 Previous Next

Raspberry Pi Model B+

17 posts

Can you learn with Minecraft?

 

The Raspberry Pi is the ideal platform for learning and there are two great ways to learn coding, and they are physical computing and Minecraft.

  • Physical computing merges the code with electronics to produce all manner of cool projects. We can use all manner of electronic components, such as ultrasonic sensors as inputs and LEDs or buzzers as outputs.
  • Minecraft is also an exciting way to introduce coding and by mixing these two ideas together we can create an exciting introduction to the world of coding and hardware hacking.

BplusLES.jpg

 

 

The B+ has been designed for embedded projects and can be easily integrated in to many physical projects such as robotics, scientific data collection and flight capable projects.

 

Attaching an add on board to the B+ is managed in exactly the same manner as previous models thanks to a standardised 40 pin GPIO. The first 26 pins of the GPIO are fully compatible with the A and B series of Raspberry Pi, enabling you access to a wealth of great add on boards. The B+ comes with a 40 pin GPIO just like the B+ and this enables future add on board to use the new HAT specification from the Raspberry Pi Foundation. The HAT specification uses pins 27 and 28 of the new GPIO to communicate between the add on board and the Raspberry Pi, enabling the board to instruct the Pi as to how it should be configured.

 

GPIO.png

 

What better introduction to your new Raspberry Pi B+ than to delve in to the world of Minecraft and learn a little Python and electronics along the way.

 

Getting Started with Minecraft

 

Minecraft is a game created by Swedish programmer Markus "Notch" Persson and later developed and published by the Swedish company Mohjang since 2009. In recent news Minecraft is now owned by Microsoft, who purchased Mohjang in November 2014 for $2.5 billion.

 

Minecraft is available on most platforms, from cell phones to Playstation 4. But where it is most interesting is on the Raspberry Pi.

 

Why is it interesting on the Raspberry Pi?

The Raspberry Pi version of Minecraft comes with a Python API
(Application Programming Interface) that enables us to interact and alter the Minecraft world using Python and as we are using Python we can also like our Minecraft projects to the real world thanks to the GPIO and the Rpi.GPIO Python library.

 

As of September 2014 the latest version of Raspbian comes with Minecraft pre-installed and ready for hacking and this is the easiest way to start this project. You can download the latest Raspbian and find full instructions on how to copy it to your micro SD card via the Raspberry Pi website http://www.raspberrypi.org/downloads/.

 

Getting started

With Raspbian installed on your micro SD card, connect all of the peripherals required to your Raspberry Pi, remember to attach the power last. Switch on your Raspberry Pi B+ and wait for it to boot.

If this is your first boot then the raspi-config application will automatically load and ask you to configure your Raspberry Pi. At this stage we do not need to enable any special configurations, so you can move the cursor to Finish and press Enter to exit the application.


Your Raspberry Pi will now ask you to login, and the default login details are

 

Username: pi
Password: raspberry






























































 

When typing in your password the screen will not print the password to the screen, this is a normal security feature for Linux and prevents anyone from snooping your password from afar.

You will now see a prompt waiting for input, type in the following and then press enter.

 

startx































































After a few seconds the familiar Raspbian desktop will be loaded ready for use.

Firstly open a terminal using LXTerminal and type in the following and then press enter.

 

sudo idle &































































This load the idle Python editor with root priveleges, something that is needed in order for us to use the GPIO in our projects. You may be wondering what the “&” does? Well this is a Linux trick to inform the operating system that the command being run, in this case “sudo idle”, should be run and then put in to the background. This frees up the terminal for any other commands that we wish to run. With idle ready to hack, change to the Raspberry Pi second desktop via the desktop switcher in the bottom left of the screen. You can easily change back later. We do this as Minecraft has a habit of running it's window over all the other windows on the screen.

 

On the second desktop double left click on the Minecraft icon to load the application. Start a new game and create a new world. If you already have a world, you can load up that world instead. Once loaded you will be dropped inside of the Minecraft world. Take some time to look around and get a feel for the controls.

 

  • Mouse – Controls where Steve looks
  • Left Mouse Button – Destroys blocks
  • Right Mouse Button – Places blocks
  • W – Moves Steve forward
  • A – Moves Steve left
  • S – Moves Steve backwards
  • D – Moves Steve right
  • E – Opens the inventory of all block types available
  • Esc – Back to menu

 

Now that you are familiar with the Minecraft world, press the Tab key to release your mouse and return to the first desktop via the desktop switcher in the bottom left of the screen.

 

To build this project you will need

 

 

In this blog post we will discover more about the B+ and Minecraft via three simple to learn projects.

These three mini projects are

 

Project 1: Writing to the chat - Our “Hello World” test to make sure that everything is set up accordingly.

Project 2: Push button teleport - Linking the physical world with the digital, using a push button to teleport Steve around the Minecraft world.

Project 3: Control an LED – It would be great to use an LED to indicate that our teleporter is working.

 

Project 1 – Writing to the chat window

Minecraft has a built in chat window, which enables players in multi-player games to talk amongst one another. In this tutorial we will use this chat system as an output for messages from Python.

 

During our setup we have already loaded Minecraft and it is waiting for us on the second desktop. But before we go back to Minecraft, let us create a new file in idle, click on File >> New Window to launch a new blank document for our project.

 

idle_Blank.png

 

We start our project by enabling the Minecraft API for Python, and to do this we import the Minecraft module into our project.

 

 

You'll see that we import the module “mcpi.minecraft” and change it's name to just “minecraft” we do this as it makes it easier to work with.

With the import complete we move on to the next line of code.

 

 

In this line of code we create a variable, a container, called “mc” and in the variable we store the string “minecraft.Minecraft.create()” which will create a connection between our Python project and Minecraft.

 

Our final line of code simply calls the postToChat function and we pass if the string “Hello World”, not very original but a great test to make sure that everything is working.

 

 

To run your code, firstly you will need to save it, and to do this click on File >> Save. Save it to your home directory and give the file a name, but please do not save it as minecraft.py or Minecraft.py as this may cause issues in future.

With your project saved click on Run >> Run Module and then quickly switch back to the desktop with Minecraft using the desktop switcher icon.

 

You should see this on the screen.

 

IMG_20141201_140456865.jpg

 

Extension Activity – Countdown

 

Now that we have a method to post to the chat window, let's use it to create a countdown.

 

Using the code that we just created as a base let's alter it to meet our needs.

 

 

As you can see in the code we import the sleep function from the time module, this enables us to control the speed of our project. Next we create a new variable called “n” in which we store the integer 5 this will be the start of our countdown. We next use a conditional statement that states.

 

While the value of “n” is greater than 0
Post it's value to the Minecraft chat window
Sleep for 1 second
Change the value of “n” by subtracting 1 from it's current value.



















 

Try this code in your project and quickly switch back to Minecraft. You should see the chat window appear and a countdown happen.

 

IMG_20141201_140528710.jpg

 

Project 2 – Push button teleport

During our setup we have already loaded Minecraft and it is waiting for us on the second desktop. But before we go back to Minecraft, let us create a new file in idle, click on File >> New Window to launch a new blank document for our project.

 

idle_Blank.png

 

We start our project by enabling the Minecraft API for Python, and to do this we import the Minecraft module into our project.

 

 

This is followed by three further imports, the first RPi.GPIO enables access to the GPIO. We again import sleep from the time module, and finally we import the random integer function from the random library, we will use this to select random numbers later in the project.

 

 

Our next two lines of code handle the GPIO. The first instructs the module that we will be using the Broadcom pin mapping for our GPIO pins (refer to the GPIO layout image for reference) The second line instructs the GPIO library that pin 17 is an input and that we will set it to be high by default.

 

 

In our next section of code we create an infinite loop using while True: Inside of this loop we create a condition that says.

 

If the button attached to pin 17 is pressed
Choose a random number between 0 and 100
Choose a random number between 0 and 100
Choose a random number between 0 and 100
Wait for the button press to finish
Get the players current position in the game world
Change the players position using the values stored in a,b,c (these correspond to x,y,z)
Post to chat “Energize” because I am a Star Trek geek.
Wait for 5 seconds and then the process repeats.




















































 

Type this code into IDLE and save the file. Now we will build a simple circuit using the hardware components. Connect up the components as per the diagram.

Teleporter - Project 2.png

 

When your wiring is complete, run the project in idle via Run >> Run Module and then quickly swap back to Minecraft using the desktop switcher. When ready press the button on your breadboard.

 

IMG_20141201_160333633_HDR.jpgIMG_20141201_160338943.jpg

 

Steve will be teleported to a new location on the map, if he gets stuck press the button again.

 

Project 3 – Adding an LED to our teleporter

For our last project we expand upon Project 2 by adding a physical output to our teleporter. So let's take a look at the code.

 

We will reuse the code from project 2.

 

 

Our first addition is setting up pin 27 as an output, we will attach an LED to this pin later in the project.


 

When the button is triggered the LED will light up.

 


The LED will now turn off.




Now we will build a simple circuit using the rest of the hardware components. Connect up the components as per the diagram.

 

Teleporter - Project 3.png

 

When your wiring is complete, run the project in idle via Run >> Run Module and then quickly swap back to Minecraft using the desktop switcher. When ready press the button on your breadboard.

Steve will be teleported around the Minecraft world and the LED on your breadboard will light up.


Congratulations, you have taken your first steps with Minecraft on your Raspberry Pi B+.

 

All of the code for these projects can be found on my Github page.

The Holidays are always a pleasant time of year where families can get together and unwind, but for one person this is their busiest time.

 

santa.jpg

 

Santa Claus that well known bringer of presents is busy preparing everything that our hearts desire. He travels the world in one night but no one has a real picture of him, well all this is about to change with the Element 14 Santa Trap, cunningly disguised as a decorative Christmas tree.

 

So what are we going to build?

 

A Christmas tree which will flash lights and play music via integrated LEDs and a speaker. This is triggered via an ultrasonic sensor which will detect when a person is within 1 metre of the tree. Sneakily there is also a camera to capture Santa as he delivers our presents.

 

 

 

What kit do we need?

 

 

 

Download the code

All of the code for this project can be found on Github

 

Building the Christmas tree

For our tree we upcycled cardboard from our local grocery store using colored card and glue. We simply created a single side to illustrate the project clearly. You can build your tree using any materials that you see fit, apart from metal as that will conduct the power from your LEDs.

 

 

Wiring the LEDs

To save GPIO pins we have seven banks of LEDs. Each bank connects to one GPIO pin. We can safely power five LEDs from one GPIO pin as the current that they draw is within the Raspberry Pi limit. When using LED with the Raspberry Pi it is recommended that you use a current limiting resistor and these would be placed in line from the GPIO pin to the LEDs. Your LEDs will appear less bright but your Raspberry Pi and LED will be protected from too much current. In this project I chose not to use them as I wanted a brighter effect.

To wire the LEDs together we used female to male jumper cables and connected them to a breadboard stuck to the rear of the tree. Each bank of LEDs had their own spot on the breadboard enabling us to power banks individually and identify them. The wiring for a bank is as per the diagram below.

 

RED LED Connections_bb.png

 

Wiring the RGB LED

For the outer most parts of the tree we used some special RGB LED that can display red, green and blue colors. We used a common cathode version of the LED, which means that there is one common ground for the RGB and that all of the other pins require 3.3V of power to pick a color. When using LED with the Raspberry Pi it is recommended that you use a current limiting resistor and these would be placed in line from the GPIO pin to the LEDs. Your LEDs will appear less bright but your Raspberry Pi and LED will be protected from too much current. In this project I chose not to use them as I wanted a brighter effect.

The pin out for the RGB LED is as per this diagram, which also shows how we can wire many LED together. Grouping them by color so that when the correct GPIO pin is triggered we can pick any of the three colors or cycle through them.

RGB_bb.png

 

 

Wiring the HC-SR04 Ultrasonic Sensor

The HC-SR04 Ultrasonic sensor is a wonderful piece of kit. It emits a pulse of ultrasonic sound that will reflect off any nearby surfaces. When a reflection occurs an echo is sent to the sensor which is registered. Using a little basic maths and Python programming we can work out the distance between the sensor and the object.

Wiring up the sensor is straightforward requiring only four pins to be connected.

Pin 1 is 5V power, the HC-SR04 uses 5V logic and will happily accept the 5V power supply from the GPIO pin 2. The Trigger pin is next and this can be directly connected to pin 26 of your Raspberry Pi. The echo pin requires us to use an in-line 1k Ohm resistor as the sensor uses 5V logic which can damage the GPIO. By using a resistor we protect the GPIO pin from damage. Our last pin is GND otherwise known as Ground, this is connected to the Raspberry Pi Ground pin.

 

HC-SR04_bb.png

 

 

Building the project

Wiring the project is relatively simple, please follow the diagram to see how we wired our project for one bank. Test each bank individually before moving on to the next bank. In total we had seven banks of single colored LEDs and one bank of six RGB LED, with each of their corresponding pins being connected to a specific GPIO pin.

 

Installing our PiNoir

The PiNoir camera works especially well in low light conditions, so is well suited to capturing Santa.

To install the camera locate the black connector marked CAMERA between the HDMI and Ethernet ports.

 

B+LES.jpg

Carefully lift the top and bottom edges of the connector vertically, they will gently slide up and then stop when in place.

Remove your camera from the box and slide the ribbon connector into the CAMERA connector, ensure that the blue edge faces the ethernet port. Be careful handling the camera it is rather fragile. With the ribbon inside the connector gently push the connector edges back down, locking the ribbon in place.

 

With the camera in place, boot up your Raspberry Pi and in a terminal run

 

sudo raspi-config

 

At the menu navigate to Enable Camera and press enter. In the next screen select Enable, and then navigate to Finish, which will prompt you to reboot your Raspberry Pi. Do this and allow the Pi to reboot, thus enabling your camera.

 

Programming the trap!

Our Santa Trap follows a simple logic

  • Person triggers the sensor
  • A photograph is taken
  • The LEDs light up
  • Music is played


This is then looped so that the sequence is repeated if the sensor is triggered.

 

The libraries Pygame and PiCamera do not come installed on your Raspberry Pi and will necessitate you installing them via the terminal.

 

Open LXTerminal and type in the following, remember to press enter at the end of each line.

 

With the external libraries installed we can now safely close the LXTerminal window and refer back to the project.

 

Our Code

Let's step through the code. Starting with importing the modules that will enhance our code.

 

 

We import modules that enable us to control the speed of our project (time), permit Python to work with real times and dates (datetime) and enable us to use the GPIO pins in our project (RPi.GPIO) You will have noticed that the GPIO import is different to those before it, by importing a module as something we can rename it from the rather difficult RPi.GPIO into a more friendly GPIO.

The last three imports start with a module to play sound in our project, and this is called Pygame. Pygame is a module for those that want to build games using Python. Next we import the picamera module which enables the official Raspberry Pi Camera and the new Pi Noir camera to be used with Python.

Our last import is rather special as rather than importing the entire module or renaming it like we did the RPi.GPIO we shall just import one function from the module. The random module contains lots of great functions that can be used to add a few chaotic elements to your code, such as random numbers and choice. In this project it would be fun to introduce a random selection to our music choice, and in order to do that we will import the choice function from the random library.

 

With the imports completed lets move on to configuring Pygame.

 

In order to use Pygame and it's audio mixer we must first initialise both Pygame and it's audio mixer, and this is done via the two lines above.

Next we need to configure the project to work with the Raspberry Pi GPIO pins.

 

 

Our first line is an instruction that reduces the verbosity of any errors, in general use the GPIO warnings can be quite noisy so by setting them to False, in other words Off, we can minimise the noise. If you would rather see the warnings, for debugging purposes then you add a “#” to the start of that line, effectively commenting out the line and instructing Python to ignore it.

Next we set the GPIO to use a logical board numbering system that is really easy to work with. For a clear reference see the diagram below. For reference, the diagram contains all of the pins present on the Raspberry Pi B+, if you are using a model A or B, the GPIO will stop at pin 26.

 

j8header-large.png

 

Variables are an important part of programming. We can use them to store information like a container will hold water and variables will hold any data types that we wish to use. Strings, floats and integers can be stored and the input can be generated manually or via a multitude of sensors.. Where they are most useful is in storing data and giving it a more useful reference. For example which pin is used for the first string of LEDs? Well I can store that pin number in a variable called LED1 and then just use that reference through my code.

 

 

You can see in the code above that the first variable created is “global distance” and this differs to those after it. A global variable is a special kind of variable that can be used both inside and outside of a function. The global distance variable is used inside of our ultrasonic sensor detection function, that we will go into more detail with later.

Our other functions contain, integers which represent the GPIO pins used for our LED, strings which represent the location of the audio files played when the sensor is triggered, and lastly we store a string which will call a function for our camera. This is stored in the camera variable, and using the variable makes it really easy to use.

With our variables created, we will now use them to setup our project to use the GPIO pins. To use a GPIO pin we first need to setup what each pin does, for example LED1 (pin 8) is setup to be an output, in other words current will flow from the Raspberry Pi to the LEDs attached to the pin. We do this for all of the LED variables that we created earlier, and to the trigger pin, which will be used for initiating the ultrasonic pulse.

 

 

The same setup is done for our RGB LED, with each leg of the LED having it's own pin to denote the colour that will be chosen.

Our last GPIO setup is the pin which will be connected to the receiver component of the ultrasonic sensor. Rather than sending current from the GPIO pin, in this case the pin will be receiving current from the ultrasonic sensor. So for this pin we set it up as an input (GPIO.IN).

 

Creating a function for our Ultrasonic Sensor

The HC-SR04 is a cheap and simple sensor unit, it sends a pulse of ultrasonic sound and then awaits the return of the reflected pulse. The best way to use this sensor with Python is via a function which will contain all of the code needed to handle the sensors operation.

With functions, we first define the name of them in this case it is called “ultra”, the word (sensor) is an argument. This code is expandable so that we can add more ultrasonic sensors to the project. The (sensor) argument is passed the number of the sensor, with the first (and only sensor in this example) being sensor 0. Our next line instructs the function that we wish to use the global variable (distance) in this function.

We now create the start of an if and else conditional statement, starting with choosing the correct sensor, in this case 0. With the sensor chosen we now delay the code by 0.3 seconds, enough time to settle the sensor before use. We then create two variables, signalon and signaloff and we set them to 0. Next we instruct the trigger pin to send current to our ultrasonic sensor which will trigger a pulse to be sent.

With the pulse being triggered we want to control how long the pulse will be, so that are readings are accurate, so we use a delay of 0.00001 seconds, just enough to get a reliable result. We turn off the pulse by instructing Python to turn off the trigger pin on our GPIO.

Still inside of our if condition, we now create two while conditions. These conditions handle the capture of the time that a pulse is sent and received. So while no echo is received, we save the current time as a variable called signaloff, but when the echo is received, denoted by the number 1 in the second while condition, the current time is saved as another variable called signalon.

We now come to the last three lines of our if statement, and here we see the maths that will give us the answer we need. We create a new variable called timepassed and in there we store the answer to the equation, signalon minus signaloff. The answer is then used in another equation which will give us the distance that we need, so in this equation we ask what the answer will be for timepassed multiplied by 17000 which is the speed of sound in centimetres. With the distance found we then print the speed to the terminal for debug purposes. The else part of the conditional statement is rather simple, in that it just prints to the shell if there is an error.

 

Creating more functions

Functions are a great way to keep our code neat and tidy, and to help us localise any issues that we may face when we are debugging. After creatng the function to handle the ultrasonic sensor, we now create more functions to handle the other functionality that we require.

 

Music playback

We earlier imported the pygame library, and initialised it to work as an audio player. In order to play audio we need to create a function to handle the selection and playback of audio, and the best way to do this is via a function which takes an argument.

We first create a function called music, and this function takes an argument, in this case it is represented by x, but x will be replaced with the audio file that we wish to play. The music function consists of two lines of code, the first loads up the audio file that we wish to play, and the second line plays the audio file once.

 

Flashing our LED

On our tree we have two types of LED, the first being simple LEDs of a single colour and this function handles all of those LEDs at once! Flashing an LED with the GPIO is relatively straightforward, requiring us to turn on the power for a set amount of time and then turn off that power at the required time. But to do that to the many LEDs at once is a big job, made a lot easier via this handy function.

Just like our music function, the flash function can also take arguments, in this case being the variables used to identify the many LEDs in our project. In the code example below there are 7 different strings of LED that can be addressed, a,b,c,d,e,f,g, are the argument placeholders, but when used we will use the LED variables that we created earlier.

For easy reference


a == LED1

b == LED2

c == LED3

d == LED4

e == LED5

f == LED6

g == LED7


The function turns on LED1, LED2 off, LED3 on and LED4 off, LED5 on, LED6 off and lastly LED7 onthen waits for 0.2 seconds then reverses each of the LED so what was on previously is now off. It waits for a further 0.2 seconds and then the sequence is run again.

 

Flashing the RGB LED

Our RGB LED has four pins, the longest pin (pin 2) is the common ground (cathode) while the others refer to a particular color. By sending power to pins 1,3,4 of the RGB LED we can trigger the correct color that we require. In the script below we firstly trigger the red LED to light up, then blue, green and lastly we turn all of them off.

 

Resetting our LEDs

To keep things neat and tidy, we're created a simple little function that ensure that all of the LEDs are turned off at the start of our sequence.

 

Putting it all together

We now move on to the main body of our code.

We start by playing an audio file that tells us that the program has started correctly, I chose sleigh bells, but you can of course change this to suit your needs.

 

Now we start an infinite loop (while True) that will trigger our ultra function to ping out ultrasound and measure the distance travelled. Next we create a list (known in other languages as an array) labelled songlist that contains the three variables song1,song2,song3. Each of these variables contains the path to the audio files that we chose to play. In the next line we create a new variable called chosen, that will store the result of choosing a random entry from the songlist list. The function choice is part of the random module that we imported earlier.

 

We now create a new if else conditional statement, and this time we are evaluating the distance between the ultrasonic sensor and any persons in the room, if the distance is less than 30cm then the following takes place.

We create a variable called a, and in there we store the current time, we then convert the time into a string using a helper function called str() which converts anything inside the brackets into a string. Further work is needed with our a variable, the full time captured is rather too big, so we use something called string slicing to cut away the text that we do not need. We are only interested in the first 20 characters so using a[0:19] will cut this out and save it as the variable.

We now create a variable called alert, and in there we create a string that alerts us to Santa's presence, along with the time of the detection, which we created and saved as our variable a.

We print the alert to the shell and then move straight on to creating another variable that contains the time of the intrusion, again from the variable a, and we join the string .jpg to it, creating a filename that contains the time of the intrusion.

 

Our next section of code handles the taking of a picture using the Raspberry Pi Pi Noir camera, first of all we set the resolution of the picture to 1024 by 768 pixels, a nice size for a quick snap. We then capture a picture, and use the filename that we created earlier. Lastly we play the music that had been chosen randomly earlier.

 

Inside of the if conditional statement we now nest a for loop, that will run our two Led functions flash() and rgb() 100 times.

 

Out of the for loop, but still inside of our if statement we now instruct the code to wait for 1 second, thus ending the if statement.

 

We now move to the last part of the code, the else statement which simply prints “Waiting for Santa” and then waiting for 1 second.

 

Results

We have now built our own Santa Trap, which is also rather pleasing to both our eyes and ears.

 

Good luck trying to catch Santa!

I got assembled PiTFT 320x240 2.8 TFT, how can I connect the PI board to the display? The display  have different connector than B+.

Thanks,


--Kobi

We're sorry, but this offer is not available in your region, but please visit our Raspberry Pi B+ group on the Community where you'll find many Raspberry Pi enthusiasts like yourself!


MCM Electronics would like to know what you would do with a Raspberry Pi B+ . Comment below and enter to win one for yourself! Whether it's making a Retro Pi game console, creating a NAS or making a totally unique home automation system we would like to hear your ideas!


With+Case.jpg


The winner, chosen at random, will win a Raspberry Pi B+ & clear case as pictured above.


To Enter Follow These Two Easy Steps:  


1) Think of an exciting project you would like to create with a Raspberry Pi B+


2) Comment below before Midnight ET Sunday, August 10th.


Make sure to follow this blog so you’ll be notified when we announce the winner, who will be selected at random at Noon ET on Monday, August 11th 2014!


Contest Terms & Conditions


More about MCM Electronics:


MCM Electronics is a part of the Premier Farnell network and a sister company of element14. We are based in Dayton, OH and are a broad line distributor of electronic components, equipment and accessories for the consumer electronics industry in North America.


do you have any pictures on how to set this unit up to a hdtv that is easy to understand just want a diagram i am using a wipi as well .

RPi B+ works with I2S DACs, if:

  • four jumper wires used (different GPIO pins now)
  • AND: a Rasbian Linux Kernel Patch done (changed pinmux)

I did the patch (change three bytes in a kernel module) - works:

Raspberry Pi B+ and RPi-DAC

 

If DAC needs I2C for control - then it needs more effort to modify kernel (or wait for updated release,

even the most recent release June 2014 does not support yet).
Without the Kernel Patch and trying to use I2S - RPi - the B+ will hang.

I recently got my new Raspberry Pi Model B+Raspberry Pi Model B+ from Element 14 and knew immediately what I wanted to do with it. The added USB ports plus the higher current rating makes this Pi the perfect home server. No longer do you need an externally powered USB hub, you can simply hook a USB hard drive directly to your Pi! In addition, I will have the ability to hook up a BlueTooth USB and/or ZigBee USB explorer to create my very own internet of things (not covered in this blog).

 

This blog will teach you how to get your Pi up and running as a home server as fast as possible. In the process, we are going to have several other tools installed, primarily Webmin -- allowing you to control and configure your Raspi remotely.

 

First, let’s take a look at the new RasPi

 

sv0okIf.png?1


The new Pi comes with two additional USB ports (4 total), the standard Ethernet port, HDMI port, a MicroSD slot (instead of standard) and a headphone jack. You can purchase and check out it’s other specs here. One of the major differences from the previous versions is that it no longer has a VGA port, so investing in either an HDMI monitor or adapter is essential to follow this blog.

Parts you will need:

 

The first thing you need to do is install Win32DiskImager and insert your MicroSD card into your computer.

 

The Raspberry Pi foundation has terrific documentation for how to install their operating system. I used and recommend installing Raspbian, but NOOBS should work as well (and may be easier for new users).


Once the operating system has been flashed onto your SD card, plug it into your new Pi. Also plug in your monitor, power supply (micro USB), ethernet, keyboard and mouse.

 

wNZiX3V.png

 

You are going to want to “Expand the root system” and then set your password to something at least reasonably secure (remember that people will be able to access this through the internet). When it asks if you want to reboot, say yes.

 

After reboot it will ask you for your username and password. Your username is pi, and your password is what you just set.


Once it is done doing it’s thing, type startx to start the GUI. You will now be met by a friendly OS screen

 

0p1ZZkr.png

 

 

Note: I highly recommend you follow the rest of this tutorial through your Pi webbrowser. This will let you cut and paste the commands. Your browser window can be opened from the bottom left (near the start menu).


The first thing we are going to do is configure our Pi to be able to deliver more power to USB devices that we connect -- this is the whole point of this blog! To do this, open up LXTerminal

 

K6lwsRD.png?1

 

When you have it open, type:

sudo leafpad /boot/config.txt

 

If it asks for a password, type it in. Now go to the bottom of the file and add

 

safe_mode_gpio=4

 

 

(Note: eventually you will be able to add “max_usb_current=1” instead, but today is not that day. For now, this is how you increase the max current allowed to your USB ports)

 

Now save the file.

 

To get the settings to take effect you have to reboot. It is a good idea to do so now, as you want to check that your power supply can handle the load of an extra Hard Drive. I had an issue where I bought a crappy USB power supply that “was rated for 2 Amps”. However, it couldn't support the Pi + Hard Drive (in other words, it was not rated for 2 Amps).

 

Reboot your Pi (you can type reboot into your terminal) and then plug in your external Hard Drive. Open up your file manager (to the right of your Start menu) and you should see your external hard drive on the left.

 

S5XSNse.png?1

 

Great! You are now doing what the Model B could never do -- your Pi B+ is supplying power to it’s very own hard drive! (Yay!)


Note: To double check things, try to create a new folder or document in your hard drive. If it doesn’t work, then your hard drive might be corrupted and need to be fixed by windows. Before you freak out, double check by typing sudo touch /media/<your harddrive name>/testing.txt  -- If this creates a new file then great, if not then plug your hard drive into a windows machine and have it check for errors.

 

Installing WebMin

 

(Note: this is the tutorial I am following)

 

After you have finished celebrating, open LXTerminal again and type

sudo apt-get update

sudo apt-get install perl libnet-ssleay-perl openssl libauthen-pam-perl libpam-runtime libio-pty-perl apt-show-versions python

It might ask you if you want to take up more space, hit “Y” for yes. Now type

wget http://prdownloads.sourceforge.net/webadmin/webmin_1.690_all.deb

sudo dpkg --install webmin_1.690_all.deb

This whole process will take quite a bit of time, but when it is done it will display a message telling you to open

 

https://raspberrypi:10000/

 

Open whatever link it tells you to in your browser (not on your computer, but on your Raspi). Use the user name “pi” and the password you have been using.

 

Headless Mode

This section is not necessary, but some people will appreciate it.

 

What we want to do now is be able to communicate with your Pi from another computer. To do this, we need the ISP address of your RasPi. There are many ways to find an ISP, but the fastest that I found out is to simply do it through the webmin interface on the Pi itself.

 

To find your IP address, simply log into Webmin on your Pi and go to Webmin -> Webmin Servers index -> Scan for servers in the menu on the left. It should give you a message like “Found this server at https://192.168.0.11:10000/” -- simply type that address into the browser on another computer (connected to your network) and you will be in headless mode!


Note, when you type it in you may be greeted by a screen like the one below. Hit “proceed anyway”

 

fPzD6JV.png

 

Configuring your Home File Server

Now we are going to get our home file server set up. The first thing you want to do is go to “Un-used Modules” in the webmin interface on the left. Then click on “Samba Windows File Sharing”. It will say something like:

The Samba server executable /usr/sbin/smbd was not found. Either Samba is not installed on your system or your module configuration is incorrect.

The Samba package can be automatically installed by Webmin. Click here to have it downloaded and installed using APT.

Click on the “click here” link and it will be installed for you. (This will take several minutes so be patient)

 

Note:

While that is installing, take a look at your external hard drive and decide if you want to share the whole drive or just a specific folder. If you want to share a whole drive, then leave it the way it is. Otherwise, you should create a sub folder and put the files you want to share in it.

 

When the page says that Samba has finished installing, go to Servers -> Samba Windows File Sharing

 

Before we go forward, we are going to have to create users for Samba. In the Pi terminal

sudo useradd user

sudo passwd user

# type in a suitable password for other people to access the network

 

# create a main user in samba

pdbedit -a -u pi

# use the same password you use for logging in

 

# create a standard user

pdbedit -a -u user

# use the password for other people to access the drive

 

# now we have to give the user permissions to access the folder

sudo chmod 777 /media       # gives broad permissions

sudo chown -R user /media  # makes the user the owner


We only have a few more steps to go! From the web interface, click on “Create New File Share”

 

R9y69bT.png?1

 

Your settings should look something like this (feel free to name your drive whatever you want)

 

kym9W8s.png?1

Hit create, then immediately hit the name of your new server in the list (under ShareName). Go to “Access Control” on the bottom left and make sure to check the radio button to make “Writeable?” = Yes. Hit Save and then Save again.

 

Now, if you are running Windows you will need to “Map Network Drive.” In Windows 7 this is done by going to My Computer -> Map Network Drive (on the top bar). I believe on most windows versions you can also do it by going to Network Places and then right clicking on the folder you want to map. Name your drive an appropriate letter (I chose R: for Rasberry!)

 

It should pop up with a login screen asking you to log in with username pi, opt instead to log in with the user username we created, as well as the password. This is what your friends and family can all use to have access to your drive!

 

That does it! You now have a network drive running off of just your Rasberry Pi B+


Speed and Video Streaming Ability

I have tested that the Raspi can easily stream movies to your computer at 1080p. I tested this by downloading a 1080p file from here and opening it in VLC. It has no lag. Furthermore, the 25 second video transfers to my computer in about 10 seconds!

 

To transfer a 294 MB file took about one minute 50 seconds, an average transfer rate of about 2.7 MB/s. The file would transfer in chunks of about 30-50MB and then pause for several seconds -- I'm not sure why it has this beheavior.

 

That file (a 780p video file) opened quickly with VLC and works great (no pauses or any issues in the first couple of minutes of me watching it).


I would say this is a great home media platform, provided you don't have too many people watching movies at once. My family doesn't watch a ton of movies, so maybe someone can follow the blog and talk about their experiences in more depth.

RaspPi2-50.jpgEverything is Awesome

 

If you need an introduction to the B+B+ then biglesp has a blog which goes into the B+ in detail along with elecia whom helps to introduce those new to Raspberry Pi to get started with one; if you require a more technical list of the changes between the Raspberry Pi boards then you should look no further than the comparison chart.

 

Since its initial release the Pi has invoked inspiration in education, amongst programmers, and in hackers and makers over the years. The latest revision in the form of the B+ introduces new possibilities, believe it or not. Some have expressed disappointment that the processor at the core of the Pi not being faster and that the RAM has not increased, but realistically, it helps projects to slowly adapt to the changes of the board and work on familiar ground. Increasing the base specification for now would possibly change its target demographic because for now it is a very affordable single board computer that almost everyone knows.

 

What do the Changes Mean for Projects ?

 

There are three main changes as I see it that apply to dedicated electronics projects, the biggest change is having 40 tasty, tasty pins to play with on the B+, this means that you can now add, control, and communicate with more circuitry or devices than before. Or it means that you can use an add-on board which is designed for the Model AModel A/BB and still have pins to play with! Currently the only way to work out what the GPIO 40 pin block connects to is to read the schematic document, but I am lazy and I like looking at pretty colours so for a quick reference I created this fancy graphic:

 

GPIO.png

 

The additional pins have 9 usable as general purpose input/output (GPIO) with 3 extra ground connections. Pins 27 and 28 are used for something special, if you create or add a Pi expansion board then it can communicate via I²C with an Electrically Erasable Programmable Read-Only Memory (EEPROM) to identify itself and automate the configuration of the GPIO pins. This will be amazing in the future when expansion boards take advantage of it.

 

RaspPi2-52.jpgSo let's assume that you're using an expansion board, which may utilise all of the pins or some but you still want to add something else - perhaps you're wanting the Pi to act as the hub for processing the input you're sampling or capturing but you're out of direct GPIO!

 

What do we do ? there's another option which is USB, now that there are four USB ports on the Pi we can add hard drives for storage, webcams for eyes or even communicate to other prototyping boards such as the Arduino while using the USB as serial ports for communication.

 

Oh wait, that's two changes, the third is a bit simpler: board holes! if we're working on a project then we want the board to be stable. So unlike the previous models we can now mount the board onto something or use the holes to secure it within housing such as a 3D printed case3D printed case.

 

Give me an Example!

 

I journey a lot in my car, it was broken into this year as well and I want to monitor how much I use it. I could develop the Pi into a car alarm but I'm interested in using it for more than just that. I like statistics and monitoring, they can produce patterns and sometimes help to predict what's going to happen or at least just show you something that's thought provoking; at least I think so.

 

So let's use the Raspberry Pi B+ for this project idea, first it needs to be powered and for that we have a number of choices:

 

  • Create circuitry or grab an adapter to handle powering it from the car battery / lighter socket
  • Use a battery pack connected to the microUSB port
  • Plug in an expansion board such as the MOPI
  • All of the above

 

I think in this case I would use the MOPI, it can handle and recharge batteries directly connected to it and allow for hot-swapping of the batteries; this can work in conjunction with a connection to the microUSB so that it will continue to operate when not powered from the 'mains'. So in this case it can run from the cigarette lighter socket (so as to not drain the battery when the car's not running) and it can have programmed intelligence to handle when it's on MOPI battery and power down devices accordingly.

 

Now an important part to this is to have sensors and an interface. Since we're taking up part of the GPIO bank with a MOPI, plugging in another expansion board in series would make some sense. So in this case I may well choose the EnOcean add on boardEnOcean add on board and its sensor kitsensor kit. The MOPI can be installed with 'through headers' that allow for the addition of another expansion board while the sensors can be installed in the car to monitor the temperature and which doors / hood / boot are opened or shut.

 

So were I using a Raspberry Pi Model A or B in this case, that would be practically all of my accessible GPIO used up, not taking into account if I looked at the schematics/data sheets for the EnOcean Pi and the MOPI to see what was available. Thanks to the B+ I now have some more GPIO I can play with; but what would I use them for ? I already have all of my sensors connected thanks to the add on boards, well what would make sense to me is to control feedback from the board as to its status.

 

Let's say that we're using all 26 original pins, we now have an additional 9 to play with - with the switch(es) that the EnOcean Pi can add we could change what mode or features that the B+ has activated depending on button presses taken in by the EnOcean Pi or what's read in via the GPIO (say if we wanted to turn off use of the sensors or we just want to read temperature, or we want to turn the device off if we can no longer reach the button on the MOPI). This helps to make the jump from a possibly awkwardly accessible device that something can go wrong with (either via programming or otherwise) to a device which can now give visual feedback or we can interact with in a manner that we control.

 

So the sensors that I've connected can monitor the state of the car doors and the temperature, but I want to be able to track more. Well that's where the USB ports can now come into play where by I would connect one or more of the following:

 

  • GPS Dongle
  • WiFi Adapter / (2g/3g/4g) Mobile Dongle
  • 2.5" Portable Hard Drive
  • Webcam

 

With the above added I have now potentially made the B+ location aware, it can record what it sees and it can communicate out to the wide world either when it's in proximity to a WiFi access point or via the cell network. In fact, I could change that WiFi adapter to not just connect to an access point but to become one and from that serve web pages which can allow me to manage the system while it is installed. The last thing I would want is to have to rip the system out that I've installed into my car every time I wanted to access it.

 

More importantly, I can make it accessible from the internet. Imagine if I want to know what the status of my car is from my phone; I load up the web interface that my car is presenting (remotely thanks to the mobile dongle for example) and I can tell if any doors are open, or even have it notify me if the temperature's too high should I have a pet in the car via SMS messaging. Perhaps, if I used a sufficient lens or convex mirror I could have the webcam cover the car in a greater than normal field of view, with angular correction in software then use OpenCV and it can pick up when someone's coming up close to the car and record a snapshot to upload. Or, alternatively just a wide angle lens with/or instead use the PiCam  PiCam  connected to the CSI ribbon connector on the board.

 

Controlling the B+ in this configuration could be done with a screen either connected to the HDMI or the DSI on the board, with the available GPIO used for navigation buttons on a displayed menu. If the screen was to be a touch screen then you'd either have a 50 second response time USB connected device or one that tries to use the SPI GPIO, potentially conflicting with the other devices plugged into the board.

 

I'm Crazy

 

Yes, I know. This is an adventurous idea, with a lot of smaller projects collected together into one fantastical ideal that would take time, patience and smart power management to handle along with programming - but this is the challenge of the Internet of Things, or I guess I'm suggesting an Internet of Cars. Whether you'd want this information available to the global internet is questionable, having had my car broken into I would love to have a smarter car alarm that didn't cry wolf when the wind blew on it but what I'd also like is to not have the car alarm more of a target than the car itself. The Internet of Things doesn't necessarily have to be small and aware devices, but retro fitting technology onto what already exists to make it aware can also work.

Internal.gif

 

 

 

 

 

What are you going to make work with the B+ ?

My Raspberry Pi B+ arrived yesterday so I thought I'd take a few photos of both the B+ and the changes but also how existing boars do do not fit the B+ design!

 

PI+  Full Frontal

B+.JPG

 

B+ Network (now with Blinkin' Lights) and the all important 4 USB ports

B+ENDON.JPG

 

New 4 port USB Variant of the original 2 port device, Composite Phono has gone to be replaced with a 4 pole AV combo on the other side

B+USB4.JPG

 

The Rear has been tided up and the full sized SDcard is replaced with a nice metal  micro SD push push device!

B+REAR.JPG

 

The Micro USB power connector is now on the same side as the HDMI and the Linear regulators replaced by this Switch mode.

Expect lower supply currents and hopefully reliability !!

B+PSU1.JPG

Small CISECO Radio board fits easily no problems

B+CISECO.JPG

Unfortunately a no go with The PI Face Control and Display

B+con1.JPG

B+con2.JPG

 

Same for the Pi Face Digital

B+Piface1.jpg

 

B+Piface2.jpg

 

Adafruit's Prototyping board stands higher and thus is free of the board underneath and fits fine

b+Ada.jpg

(All images My copyright)

 

As you can see they a have taken many of the problems that existed in the B and have mitigated them in the B+.

The B+ is a true incremental release in this respect the extra USB ports and SMPs PSU should improve functionality and reliability.

 

Overall the physical layout changes are a great improvement  having connectors on only two sides will aid case designers and integrators alike. Large boards do foul the connectors some redesign is required for these (maybe a physical lift upwards??)

 

Extra I/O on the 40 pin connector should prove interesting as well!!

B+LES.jpg

 

The Raspberry Pi is now two years old and in it's lifetime it has found itself deep under the sea, controlling complex machinery and floating in space. The initial goal of the project, to educate children in Computer Science has revolutionised the education landscape with children and adults learning more about Computing and Electronics.

 

Revisions

Since it's initial launch there have been many Models of the Raspberry Pi

 

Model

RAM

CPU

GPIO

USB

Storage

Ethernet

AA

256MB

ARM11 700MHZ

26

1

SD Card

None

B (Rev 1)

256MB

ARM11 700MHZ

26

2

SD Card

10/100

B (Rev 2)

512MB

ARM11 700MHZ

26

2

SD Card

10/100

ComputeCompute

512MB

ARM11 700MHZ

120

1

EMMC flash storage

None

B+B+

512MB

ARM11 700MHZ

40

4

Micro SD Card

10/100

 

 

mechanicalspecB+.png

 

Introducing the Model B+

 

At 7am BST the Raspberry Pi Foundation officially launched the new Model of the Raspberry Pi. The Model B+, is considered the final version of the Model B and uses the same Broadcom BCM2835 SoC that is present on all of the previous Raspberry Pi revisions. By basing the Model B+ on an existing architecture the Foundation have smartly retained compatibility with the existing software and projects that have been previously developed.

 

The Model B+ provides a more refined product based on feedback received from the community, and here are a few of those refinements.

 

Hardware

BplusLES.jpg

 

 

The B+ measures 85 x 56 x 17mm in size, slightly smaller than the original form factor. With this size reduction comes an improved layout and organisation of the board and looking around the board there are a number of changes present.


Most noticeably is the layout of the ports. Instead of being dotted around the perimeter of the board, as in previous models, the B+ only has ports on two sides of the board. With this new layout comes a few improvements, noticeably the increase of USB ports present, courtesy of the new LAN9514 chip as opposed to the older LAN9512 used on previous models.


By doubling the number of ports to 4 the B+ can have more devices attached including external hard drives thanks to the ports supporting a higher current, enough for most portable USB2 hard drives. Hot swapping of USB devices is now more stable, a very welcome addition for those that encountered the USB reboot issue present on previous models.


The Ethernet port remains the same as the Model B, running at 10/100. But you will now see that the USB and Ethernet ports are now level on the board, which will be great news for case manufacturers.

Moving further round the board you will see a 3.5mm headphone connector which on the original Raspberry Pi provided audio output only. But for the B+ this connector also supplies video in place of the now missing composite RCA socket, this is thanks to it now boasting 4 poles. To use this new port with your Composite connected TV you will need to purchase an adaptor. Analogue audio output has been vastly improved for the B+ as in the previous Models this was a little under developed.


Moving over the HDMI port, the last port is the micro USB rated for 5V 2A which is connected to a much improved power circuit enabling greater power efficiency, a welcome addition for those using their Pi for robotics where batteries are the norm. The power circuit also provides a greater tolerance for cheaper, under powered power supplies.

For the upcoming official Raspberry Pi touchscreen display and the existing Pi Camera there are the same DSI and CSI ports, but they are now helpfully labelled DISPLAY and CAMERA.


The Model A and B Pi have all used SD cards as their data storage device, but in a smart move by the Foundation they have replaced standard SD with a rather robust and tactile Micro SD slot with a push locking mechanism. With the cost of Micro SD cards coming down in recent years this gives the end user a cheap, plentiful source of cards with full compatibility with all Models of Raspberry Pi.

 

IMG_20140714_080641851.jpg

 

 

The previous Model A and B Raspberry Pi came with a 26 pin GPIO, but the B+ comes with a larger GPIO (General Purpose Input Output). Now sporting 40 pins of which 26 can be used by the user, and there are 3 extra GND pins.


The previous Model A and B had 26 GPIO pins, and these pins are still present, with the extra 14 adding to the series of pins. By ordering the pins in the same manner as previous Models the B+ can be used with the majority of the add-on boards currently on the market.


bplus-gpio.png



I was keen to know if the expanded GPIO impeded the use of the many add-on boards on the market. So I tested the B+ with the popular Pibrella board from Pimoroni and I am happy to report that it worked flawlessly. For the majority of boards this will be the case, and I am keen to test my other boards with the B+.

 

IMG_20140714_080142684.jpg

 

I tested the B+ with the latest NOOBS release, downloading and copying the install files with ease. NOOBS worked just as I expected and installed Raspbian in about 10 minutes. Once installed and rebooted I was back in familiar territory with everything working as expected.

 

Verdict

The B+ is a refined and well thought out product, it expands the firm foundation of the previous Raspberry Pi models and provides a great middle ground between the 26 GPIO pins of the Model A and B and the 120 pins of the Compute module. The B+ covers many project types and provides everything that advanced users will need for their makes.


Keeping the price in parity with the Model B is fantastic and enables informed purchases to be made with ease.

 

You can purchase your Model B+ via the product page on Element14Model B+ via the product page on Element14.

elecia

Welcome to the B+

Posted by elecia     Jul 14, 2014

Element14 sent me a new Raspberry Pi B+ board to evaluate. The verdict is easy: I don’t know why it took me so long to pick one of these up, I was completely charmed.

BPlusInfographic.jpg

The B+ has the same processor, clock speed, and RAM (512MB) so the huge community’s existing programs will run without update. It has the same camera and display connectors so your existing accessories will be compatible. Oh, and it has the same price. It has two additional USB ports (four in total) so you may do away with your powered hub. Additionally, the power available to the USB ports can be increased up to 1.2A, settable via an operating system switch. With a 5V and 2A power supply unit, the B+ can power a 2.5” USB hard drive off the Pi.

 

If you forego the USB accessories, this Raspberry Pi will last longer on a battery since it consumes only 600mA (instead of 750mA for the B). My project ideas tend to involve carrying the device around so I’m happy to hear this.

 

Folks who are currently using pin expanders may be happy about the increased number of GPIOs, which are now up to 40 (with the first 26 pins being backward compatible to the Model B).

 

BPlusPinout.png

I was also glad about the micro SD card slot instead of a full size SD as my camera uses those. (You can see how the new Raspberry Pi Model B+ compares to the earlier versions here.)

 

Since I am an RPi newbie, I watched element14’s Get Started with Pi videos, bought it a wireless keyboard and mouse, downloaded NOOBS onto a microSD card, and read Make’s Getting Started with Raspberry Pi. Upon receipt of the B+, I hooked it up and started playing with it.

 

When I was eight years old, we had a Commodore 64 attached to the living room TV. Everyone could see what I was doing: my brother would try to take the keyboard and point out typos, my mom would shake her head and tell me to get my glasses, someone would eventually want the TV and I’d be done for the afternoon. I entered programs from magazines (or scraps of paper from other children of similar disposition) and each time I reset the system, they’d be gone.

 

I learned a lot from those days. I was delighted to get the same feeling from the Raspberry Pi B+. Once again, I was in the living room, squinting up at the TV. I played with Scratch, the for-kids programming language. My eight-year-old self would have adored that. I fired up python, a language I tend to use for short scripts, that I would love to properly learn.

 

This time I had electronic books: I knew with a little effort I could cut, copy, and transfer snippets over, but, for the first hour, retyping was easier. I’d forgotten that typing in someone else’s code is a really good way to learn. For that alone I’m happy to have gotten to work with the Raspberry Pi. The whole system is designed to make you want to learn things.

 

Since I have some ideas about modelling animal vision, I got a Pi Camera and NoIR Pi Camera. Hooking them each up was easy, raspistill and raspivid worked well. Now I have some software to play with and a board that is rife with possibilities. I have a whole project planned out. It will be awesome. I hope. But that's later: the hardware is what matters here.


Welcome to the Raspberry Pi B+!


raspistill_bear.JPG

(Note: I did eventually get myself an HDMI monitor, the crick in my neck reminded me that developing on my desk had some overwhelming advantages. Sadly, I’m not eight years old anymore.)

 

Internal.gif

Vergangene Woche habe ich erläutert, wie Sie eine Web-API mit Windows Azure, ASP.Net und C# erstellen können.
Diese Woche verbinden wir das Ganze mit unserer ursprünglichen Pi Passport Klassifizierung. Da unser System in verschiedene Ebenen unterteilt ist, sollten wir hier eigentlich nur die Datenebene anpassen müssen.
An dieser Stelle nochmal zur Erinnerung – so sah unser Projekt vor zwei Wochen aus:


Hier läuft quasi alles über zwei xml-Dateien, von denen eine Datei alle Daten zu unseren Aktivitäten und die andere Daten zur Person enthält.
Jetzt, da wir eine Web-API haben, werden Personen im Internet und Aktivitätenbeschreibungen dort oben gespeichert. Fragen und Antworten zu Aktivitäten kommen jedoch direkt auf den Pi, da wir den Interwebs nicht unbedingt entnehmen müssen, wie ein Benutzer eine Aktivität erreicht hat – wichtig ist nur, dass wir wissen, DASS er sie erreicht hat. Ein paar Hintergrundinformationen zur Aktivität sind an dieser Stelle ebenfalls hilfreich. Allerdings kann es passieren, dass das Ganze dadurch ein wenig unübersichtlich wird. Es ist wichtig, dass die IDs mit dem Server übereinstimmen, da am Ende sonst die Aktivitäten-IDs auf dem Pi von denen, die auf dem Server angegeben sind, abweichen.
Deshalb müssen wir hier Folgendes beachten:
- Ändern Sie Speichern/Laden von Personen, um Requests ausführen zu können.
- Ändern Sie Speichern/Laden von Aktivitäten, um Requests ausführen zu können und achten Sie darauf, dass die IDs zueinander passen.
- Ändern Sie die Parameter der Klassifizierung so, dass die URLs, die wir aufrufen müssen, zu den APIs passen.
- Passen Sie die Read-/Admin-Dateien so an, dass die Parameter zur Erstellung der Klassifizierung stimmen.
Lassen Sie uns mit dem LoadPi anfangen:

  1. def LoadPi(self): 
  2.       dom=self.Load(self.pi,"piSyst"
  3.       try
  4.            pi_tag=dom.getElementsByTagName("pi")[0
  5.       except
  6.            self.SavePi() 
  7.            dom=self.Load(self.pi,"piSyst"
  8.            pi_tag=dom.getElementsByTagName("pi")[0
  9.  
  10.       a_q=requests.get(self.pi_url) 
  11.       a_data=a_q.json() 
  12.       a_dict={} 
  13.        for a in a_data: 
  14.            a_dict[a["ID"]]={"Description":a["Description"]} 
  15.       pid=pi_tag.getAttribute("ID"
  16.       a_tags=pi_tag.getElementsByTagName("achievement"
  17.       achievements={} 
  18.        if int(pid) in a_dict.keys(): 
  19.             achievements[pid]={"question":None,"answers":None,"Description":a_dict[int(pid)]["Description"]} 
  20.       else
  21.            desc=raw_input("Please enter a description for this pi:"
  22.             post=requests.post(self.pi_url,data=json.dumps({"Description":desc}),headers={"Content-type":"application/json"}) 
  23.            id=str(int(post.json()["ID"])-1
  24.            achievements[id]={"question":None,"answers":None,"Description":desc} 
  25.            pi_tag.setAttribute("ID",str(id)) 
  26.            file=open(self.pi,'w'
  27.            dom.writexml(file) 
  28.            a_q=requests.get(self.pi_url) 
  29.            a_data=a_q.json() 
  30.            a_dict={} 
  31.             for a in a_data: 
  32.                 a_dict[a["ID"]]={"Description":a["Description"]} 
  33.             for a in a_tags: 
  34.                 id=a.getAttribute("ID"
  35.                 qtag=a.getElementsByTagName("question")[0
  36.                 question=qtag.childNodes[0].data 
  37.                 atag=a.getElementsByTagName("answer"
  38.                 answers=[] 
  39.                 for an in atag: 
  40.                      answers.append(an.childNodes[0].data) 
  41.                  achievements[id]={"question":question,"answers":answers,"Description":a_dict[id]["Description"]} 
  42.  
  43.       return achievements 


An dieser Stelle müssen Sie Requests installieren. Das ist so ähnlich wie urllib, aber wesentlich einfacher zu verstehen. Über diesen Befehl finden Sie sie auf PyPip:
sudo pip install requests
Wir arbeiten uns hier Schritt für Schritt durch:

  1.       dom=self.Load(self.pi,"piSyst"
  2.       try
  3.            pi_tag=dom.getElementsByTagName("pi")[0
  4.       except
  5.            self.SavePi() 
  6.            dom=self.Load(self.pi,"piSyst"
  7.            pi_tag=dom.getElementsByTagName("pi")[0
  8.  
  9.       a_q=requests.get(self.pi_url) 
  10.       a_data=a_q.json() 
  11.       a_dict={} 
  12.        for a in a_data: 
  13.            a_dict[a["ID"]]={"Description":a["Description"]} 
  14.       pid=pi_tag.getAttribute("ID"
  15.       a_tags=pi_tag.getElementsByTagName("achievement"
  16.       achievements={} 
  17.        if int(pid) in a_dict.keys(): 
  18.             achievements[pid]={"question":None,"answers":None,"Description":a_dict[int(pid)]["Description"]} 


In diesem ersten Abschnitt passiert Folgendes:
• Die dom wird geladen und das Pi Tag gesucht.
• Falls nicht vorhanden, wird das Pi gespeichert und das dom Tag erstellt, damit es beim nächsten Mal bereitsteht.
• Es wird ein Request an die entsprechende API geschickt, alle Aktivitäten aufzulisten.
• Das JSON-Objekt wird in ein Python-Verzeichnis geladen.
• Die Pi Aktivität auf dem Server wird überprüft und eine Instanz mit den Deets dieser Aktivität erstellt.

  1. else
  2.            desc=raw_input("Please enter a description for this pi:"
  3.             post=requests.post(self.pi_url,data=json.dumps({"Description":desc}),headers={"Content-type":"application/json"}) 
  4.            id=str(int(post.json()["ID"])-1
  5.            achievements[id]={"question":None,"answers":None,"Description":desc} 
  6.            pi_tag.setAttribute("ID",str(id)) 
  7.            file=open(self.pi,'w'
  8.            dom.writexml(file) 
  9.            a_q=requests.get(self.pi_url) 
  10.            a_data=a_q.json() 
  11.            a_dict={} 
  12.             for a in a_data: 
  13.                 a_dict[a["ID"]]={"Description":a["Description"]} 
  14.             for a in a_tags: 
  15.                 id=a.getAttribute("ID"
  16.                 qtag=a.getElementsByTagName("question")[0
  17.                 question=qtag.childNodes[0].data 
  18.                 atag=a.getElementsByTagName("answer"
  19.                 answers=[] 
  20.                 for an in atag: 
  21.                      answers.append(an.childNodes[0].data) 
  22.                  achievements[id]={"question":question,"answers":answers,"Description":a_dict[id]["Description"]} 
  23.  
  24.       return achievements 


Weiter geht es mit diesem Abschnitt:
• Hier wird festgestellt, dass das Pi Tag nicht in den Serveraktivitäten gelistet ist.
• Sie werden aufgefordert, ein solches Tag zu erstellen, indem Sie der Aktivität eine Beschreibung hinzufügen. Diese wird dann mittels eines Post-Requests an den Server weitergeleitet.
• Um sicherzustellen, dass auch alles zueinander passt, wird die ID vom Server sowohl in das Aktivitätenverzeichnis als auch in die pi.xml-Datei übernommen.
• Jetzt fragt das System Sie nach einer Liste der Aktivitäten und erstellt daraus ein Verzeichnis.
• Anschließend geht es in die xml-Datei, aus der es alle lokalen Aktivitäten zieht. Die dazugehörigen Beschreibungen werden der Serveraktivitäten-Liste entnommen.
Lassen Sie uns noch den Initialisierer für die Klassifizierung ändern, bevor wir es vergessen:

  1.   def __init__(self,pifile,people_url,pi_url,link_url): 
  2.       self.pi=pifile 
  3.       self.pi_url=pi_url 
  4.       self.people_api=people_url 
  5.       self.link_api=link_url 
  6.  
  7.       self.achievements=self.LoadPi() 
  8.       self.people=self.LoadPeople() 


Hier haben wir immer noch die Pi Datei – das ist eine xml thingymagig, die alle Daten zu jeder Aktivitätenfrage enthält. Allerdings haben wir auch noch drei API-Links: einen für Aktivitäten (pi_url), einen für Personen (people_api) und einen für Links (link_api).
Jetzt gehen wir zurück auf SavePi:


Die Vorgehensweise ist wieder ähnlich – wir speichern alle Aktivitäten in der Pi Datei und prüfen, ob sie auch auf dem Server vorkommen. Das tun wir, indem wir alle Aktivitäten auf den Server laden und prüfen, ob sie auch wirklich im Aktivitätenverzeichnis auftauchen. Wenn sie zwar auf dem Server, jedoch nicht im Verzeichnis gelistet werden, dann löschen Sie sie vom Server. Wenn es andersherum ist, dann erstellen Sie einen Eintrag auf dem Server.
Nun geht es weiter mit SavePeople:


Anstatt eine xml-Datei zu verwenden, machen wir jetzt Folgendes:
• Stellen Sie eine Verbindung mit der API für Personen her.
• Laden Sie alle hoch.
• Verbinden Sie sie mit der API für Links.
• Laden Sie alle Aktivitäten für die Personen, die wir gerade hochgeladen haben.
• Vergleichen Sie die aktuelle Personenliste mit dieser Liste.
• Wenn einige Personen nicht auf der Serverliste auftauchen, fügen Sie sie beiden APIs mittels Post-Requests hinzu.
Vielleicht fragen Sie sich, warum wir nicht prüfen, ob die Personen auch auf der Serverliste stehen: Wir vergleichen nur die aktuelle Liste, da wir davon ausgehen können, dass Personen auf der Serverliste nur vom System überschrieben werden können.
Fast fertig – jetzt fehlt nur noch LoadPeople:


Der Prozess ist hier so ziemlich der gleiche wie weiter oben, nur andersherum.
Jetzt müssen wir nur noch read.py und admin.py anpassen, um die Änderungen an den Klassifizierungsdefinitionen zu reflektieren. Dazu müssen Sie einfach nur den ursprünglichen NFC-Klassifizierungsaufruf ändern:
self=NFC('pi.xml','http://someurl.com/api/People','http://someurl.com/api/Achievements','http://someurl.com/api/Joins')
Endlich – wir sind fertig! Wenn Sie jetzt read.py ausführen, sollte jede Person zur Datenbank hinzugefügt werden.

Links zu vorherigen Tutorials: Eins, Zwei, Drei und Vier.


In meinem vorigen Blogeinträgen haben wir Pi Passport Maschinen als eigenständige Systeme erstellt – sämtliche Daten zum Benutzer sowie alle Aktivitäten werden auf dem Pi gespeichert. Wenn Sie nicht wollen, dass Ihre Daten von einer anderen Stelle aus zugänglich sind, dann ist das völlig in Ordnung so. Für dieses Projekt ist es jedoch besser, wenn uns die Daten online zur Verfügung stehen – so können Sie anderen ganz einfach mitteilen, dass Sie an einem Jam teilgenommen haben, Ihren Freunden Ihre Aktivitäten zeigen usw.
Hierfür müssen wir etwas erstellen, dass sich REST Web-API nennt. Diese REST Web-API ermöglicht es uns, einen Request an eine URL zu schicken, um Daten abzurufen oder anzupassen. Und wie funktioniert das Ganze? Das ist eigentlich ziemlich einfach: Es gibt vier Arten von HTTP-Requests, über die eine Webseite erkennen kann, was wir machen wollen und ob wir Daten anpassen oder einfach nur abrufen. Diese entsprechen den CRUD-Methoden (Erstellen, Prüfen, Aktualisieren und Löschen) – POST (Erstellen), GET (Prüfen), PUT (Aktualisieren) und DELETE (Löschen).
In diesem Fall verwende ich Azure. Sie können aber natürlich auch einen anderen Dienst nutzen. Ich verwende Azure, weil ich Visual Studio habe (das war für mich als Studentin kostenlos), und die Erstellung von Code für eine einfache Aufgabe ist auch nicht schwierig. Also machen Sie sich keine Sorgen, wenn Sie nicht mit C# vertraut sind – das Meiste von dem, mit dem wir uns hier beschäftigen, wird sowieso automatisch erstellt. Sie können Azure auch in einer anderen Programmiersprache verwenden, da Azure Ihnen quasi keine Grenzen setzt, was den Server angeht.
Ach, und noch etwas – Azure kann man einen Monat lang kostenlos nutzen.
Wenn Sie diesen Schritt lieber überspringen möchten, dann gehen Sie einfach zum nächsten Schritt über. Requests werden sowieso immer gleich behandelt, unabhängig davon, für welchen Server Sie sich entscheiden. Eventuell stelle ich zu einem späteren Zeitpunkt nochmal eine kürzere Version dieses Tutorials bereit.


Schritt 1: Die Einrichtung von Azure
Gehen Sie als Erstes auf die Azure Webseite und klicken Sie ganz unten auf „Free Trial“ (Auf der deutschen Webseite: „Kostenlos testen“). Geben Sie hier Ihre persönlichen Daten ein (wenn Sie kein Microsoft- oder kein Hotmail-/Outlook-E-Mail-Konto besitzen, müssen Sie vorab noch eines erstellen). Klicken Sie nach der Registrierung auf das Portal ganz oben auf der Azure Startseite.
web_trial.png
Sobald der Ladevorgang abgeschlossen ist, sollten Sie das hier sehen:
web_portal.png
Klicken Sie unten links auf „New“ und wählen Sie anschließend eine der hervorgehobenen Optionen:
custom_create.png
Geben Sie alle erforderlichen Informationen ein:
create_website.png
Stellen Sie sicher, dass der Name Ihrer Webseite richtig ist und nicht von anderen Benutzern verwendet wird – da es sich hierbei um einen Shared Hosting-Plan handelt, kann theoretisch jeder Nutzer, der den gleichen Namen wie Sie hat, in Azure auf Ihre Webseite zugreifen ...
Klicken Sie auf den Pfeil unten rechts und geben Sie alle erforderlichen Informationen zur Datenbank ein:
create_database.png
Klicken Sie auf das Häkchen – und schon haben Sie eine neue Webseite und eine Datenbank erstellt, in der Sie alle Informationen speichern können.
Jetzt können wir mit dem Schreiben von Code loslegen. Wenn Sie Visual Studio nicht haben, können Sie alle erforderlichen Daten im Download-Bereich herunterladen:
downloads.png
So bekommen Sie zumindest VS express.
Ich selbst verwende VS2013 – wenn Sie noch Student bzw. Studentin sind und über Ihre Uni an Dreamspark herankommen, dann sollten Sie auch diese Version kostenlos herunterladen können. Diejenigen unter Ihnen, die ein Upgrade benötigen, müssen mindestens mit der Version 2012 arbeiten.


Schritt 2: Erstellung des Projekts & Hochladen in Azure
Wenn Sie VS jetzt öffnen und entweder im Dateimenü oder auf der Hauptstartseite auf „New Project“ klicken, wählen Sie unter „Templates -> Visual C#“ bitte „Web“. Jetzt sollte Ihnen nur die ASP.NET Web App-Option zur Verfügung stehen. Geben Sie Ihre Daten ein und klicken Sie auf „OK“.
Jetzt sollte ein neues Pop-Up erscheinen – klicken Sie hier auf „Change Authentication“.
no_auth.png
Der Einfachheit halber entscheiden wir uns jetzt gänzlich gegen eine Authentifizierung. Bei Release-Versionen ist es wahrscheinlich angebrachter, hier eine sicherere Variante zu wählen, aber für den Anfang lassen wir das jetzt einfach so stehen.
Zusätzlich dazu müssen Sie folgende Optionen wählen:
other_options.png
Klicken Sie erst auf „OK“ und in der nächsten Box dann auf „Cancel“.
Machen Sie einen Rechtsklick auf das Projekt im Solution-Explorer und wählen Sie „Publish“:
click_publish.png
Klicken Sie jetzt auf „Windows Azure Websites“ – hier finden Sie Ihr Webseitenprofil in einer Dropdown-Liste.
So sollten Sie Ihr Profil laden können. Sollte die Dropdown-Liste leer sein, klicken Sie auf „Import“ und geben Sie Ihre Anmeldedaten für Azure ein. Klicken Sie in der nächsten Ansicht auf „Validate Connection“:
publish.png
Jetzt sollte rechts neben der Schaltfläche ein gelber Haken angezeigt werden.
Klicken Sie nun zweimal auf Weiter.
Anschließend klicken Sie bitte auf „Start Preview“:
preview.png
Die Liste wird nun mit allen Daten, die hochgeladen werden, befüllt. Jetzt schauen wir uns einmal die URL an:
asp.png
Wir haben eine Webseite – die nichts kann.


Schritt 3: Aufbau der Infrastruktur
Übrigens erstellen wir hier eine MVC-Anwendung – „MVC“ steht dabei für Model View Controller. So wird die Anwendung quasi in verschiedene Ebenen aufgeteilt. Dabei erstellt sich das „Model“ selbst anhand der Daten aus der Datenbank und verwaltet sämtliche Updates und Änderungen. Der „Controller“ verwaltet die Interaktionen zwischen „Model“ und „View“, und „View“ ist die Benutzerschnittstelle, die uns die Anpassung von Daten ermöglicht.
Jetzt erstellen wir unser erstes Modell, also klicken Sie mit rechts auf den Modellordner und anschließend auf „Add -> Class“:
model.png
Im nächsten Pop-Up wählen Sie den ersten Eintrag aus der Liste (Class – also Klassifizierung) und benennen ihn in „Person.cs“ um – in C# ist es üblich, dass Klassifizierungen mit Großbuchstaben und Variablen mit Kleinbuchstaben anfangen.
Wählen Sie die neue Klassifizierung im Modellordner aus und geben Sie Folgendes ein: Gar nicht mal so anders als Python. Einzüge? Ach ja, die kann man natürlich auch noch einfügen. (Das ist ernst gemeint, denn so sieht das Ganze wesentlich übersichtlicher aus – mehr können Einzüge aber auch nicht.)

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Web; 
  5.  
  6. namespace Passport.Models 
  7.     public class Person 
  8.     { 
  9. public string ID { get; set; } 
  10. public string name { get; set; } 
  11.     } 


Und hier ein kurzer Tipp von mir als Python-Benutzerin zu C#: „Using“ in Python wäre in diesem Fall „Import“. Weiterhin können wir innerhalb eines Projekts verschiedene Klassifizierungen mit dem gleichen Namen erstellen, ohne Sorge haben zu müssen, dass wir sie verwechseln könnten. „Public“ bedeutet, dass auf die Klassifizierung und die Variablen auch von außerhalb des Bereichs zugegriffen werden kann, in dem sie erstellt wurden.
Jetzt richten wir hierfür einen Controller ein, indem wir mit rechts auf „Controllers -> Add -> Controller“ klicken.

Wählen Sie den Befehl „Web API 2 Controller with actions using Entity Framework“.

controller.png
Im nächsten Fenster können Sie Ihre neue Personenklassifizierung auswählen:
con_2.png
Klicken Sie auf die Schaltfläche mit einem Plus, die sich neben „Data Context“ befindet. Lassen Sie dies als Standard stehen und klicken Sie anschließend auf „OK“ und „Add“.
Befolgen Sie die obenstehenden Schritte noch zwei weitere Male, jetzt allerdings für die Aktivitäten und einen Join Table. Jede Aktivität wird über folgende Eigenschaften verfügen:
Eine ID
Eine Beschreibung
Jeder „Join“-Eintrag wird über folgende Eigenschaften verfügen:
Eine ID
Die ID des Benutzers, der die Aktivität ausgeführt hat
Die ID der ausgeführten Aktivität
Ich hoffe, dass ich den Prozess einigermaßen verständlich erklären konnte.
Sobald Sie alles erstellt haben, führen Sie Ihr Projekt aus (F5 oder die große Schaltfläche mit einem grünen Pfeil):
run.png
So überprüfen Sie, ob alles passt. Jetzt sollte sich ein Web-Browser öffnen, in dem der lokale Host sowie eine Port-Nummer angezeigt wird. Geben Sie nach dem Slash „/api/People“ ein:
Jetzt sollte das Ganze so aussehen.
api.png
Sie können den Vorgang auch anhalten, indem Sie zurück auf Visual Studio gehen, hier auf „Stop“ klicken und anschließend neu laden:
republish.png
Wenn in Ihren Datenbanken nichts angezeigt wird, gehen Sie noch einmal in die Einstellungen und passen Sie diese wie folgt an:
sett.png
Überprüfen Sie wieder, ob es online funktioniert – und dann sind wir auch schon fertig. Im nächsten Tutorial zeige ich Ihnen, wie wir dieses Projekt mit Python auf dem Pi verbinden.
Die Erstellung der Webseite, auf der Sie Ihre Aktivitäten anzeigen und mit anderen teilen können, ist etwas aufwändiger. Aus diesem Grund werde ich darauf in dieser Tutorial-Reihe nicht weiter eingehen.

Links zu vorherigen Tutorials: Eins, Zwei und Drei.

Im letzten Beitrag zu unserem PiPassport Projekt haben wir gemeinsam eine Klassifizierung für NFCs erstellt, mit denen wir einzelne Benutzereinträge sowie auch
Aktivitäten an verschiedenen Stationen speichern und laden können.
Nach dem letzten Tutorial sollte Ihre nfc.py-Datei in etwa so aussehen:

  1. import nxppy 
  2. import os,json,requests 
  3. from xml.dom import minidom 
  4.  
  5. class NFC(object): 
  6.             def __init__(self,pifile,peoplefile): 
  7.                         self.pi=pifile 
  8.                         self.peoplef=peoplefile 
  9.  
  10.  
  11.                         self.achievements=self.LoadPi() 
  12.                         self.people=self.LoadPeople() 
  13.  
  14.             def ReadCard(self): 
  15.                         id=nxppy.read_mifare() 
  16.                         if id == None
  17.                                     return None 
  18.                         else
  19.                                     if id not in self.people.keys(): 
  20.                                                 print "new ID :", id 
  21.                                                 name=raw_input('Please enter your name:'
  22.                                                 self.people[id]={"name":name,"achievements":[]} 
  23.                                     else
  24.                                                 for aid in self.achievements.keys(): 
  25.                                                             if aid not in self.people[id]['achievements']: 
  26.                                                                         if self.achievements[aid]['question']==None
  27.                                                                                     self.people[id]['achievements'].append(aid) 
  28.                                                                                     print "Achievement unlocked!" 
  29.                                                                         else
  30.                                                                                     print self.achievements[aid]['question'
  31.                                                                                     ans=[] 
  32.                                                                                     for a in range(len(self.achievements[aid]['answers'])): 
  33.                                                                                                 answer=raw_input('Enter answer:'
  34.                                                                                                 ans.append(answer) 
  35.                                                                                     correct=0 
  36.                                                                                     for an in range(len(ans)): 
  37.                                                                                                 found=False 
  38.                                                                                                 for answ in self.achievements[aid]['answers']: 
  39.                                                                                                             if answ==ans[an]: 
  40.                                                                                                                         found=True 
  41.                                                                                                                         break 
  42.                                                                                                 if not found: 
  43.                                                                                                             print "answer " + str(ans[an]) + " incorrect!" 
  44.                                                                                                 else
  45.                                                                                                             correct+=1 
  46.                                                                                     if correct == len(self.achievements[aid]['answers']): 
  47.                                                                                                 print "achievement unlocked!"             
  48.                                                                                                 self.people[id]['achievements'].append(aid) 
  49.                                     self.SavePeople() 
  50.                                     return self.people[id] 
  51.             def Load(self,file,type): 
  52.                         if os.path.exists(file): 
  53.                                     source=open(file) 
  54.                                     try
  55.                                                 dom1=minidom.parse(source) 
  56.                                     except
  57.                                                 impl=minidom.getDOMImplementation() 
  58.                                                 dom1=impl.createDocument(None,type,None
  59.                                     return dom1 
  60.                         else
  61.                                     impl=minidom.getDOMImplementation() 
  62.                                     doc=impl.createDocument(None, type,None
  63.                                     return doc 
  64.  
  65.             def LoadPi(self): 
  66.                         dom=self.Load(self.pi,"piSyst"
  67.                         try
  68.                                     pi_tag=dom.getElementsByTagName("pi")[0
  69.                         except
  70.                                     self.SavePi() 
  71.                                     dom=self.Load(self.pi,"piSyst"
  72.                                     pi_tag=dom.getElementsByTagName("pi")[0
  73.                         a_tags=pi_tag.getElementsByTagName("achievement"
  74.                         achievements={} 
  75.                         achievements[pi_tag.getAttribute("ID")]={"question":None,"answers":None
  76.                         for a in a_tags: 
  77.                                     id=a.getAttribute("ID"
  78.                                     qtag=a.getElementsByTagName("question")[0
  79.                                     question=qtag.childNodes[0].data 
  80.                                     atag=a.getElementsByTagName("answer"
  81.                                     answers=[] 
  82.                                     for an in atag: 
  83.                                                 answers.append(an.childNodes[0].data) 
  84.                                     achievements[id]={"question":question,"answers":answers} 
  85.                         return achievements 
  86.  
  87.             def SavePi(self): 
  88.                         dom=self.Load(self.pi,"piSyst"
  89.                         top=dom.documentElement 
  90.                         if(len(dom.getElementsByTagName("pi"))==0): 
  91.                                     pi=dom.createElement("pi"
  92.                                     id=0 
  93.                                     pi.setAttribute("ID",str(id)) 
  94.                                     top.appendChild(pi) 
  95.                                     file=open(self.pi,'w'
  96.                                     dom.writexml(file) 
  97.                         else
  98.                                     old_achievements=self.LoadPi() 
  99.                                     pitag=dom.getElementsByTagName("pi")[0
  100.                                     if old_achievements != self.achievements: 
  101.                                                 try
  102.                                                             os.remove(self.pi) 
  103.                                                 except Exception, e: 
  104.                                                             print str(e) 
  105.                                                             pass 
  106.                                                 dom=self.Load(self.pi,"piSyst"
  107.                                                 top=dom.documentElement 
  108.                                                 pitag=dom.createElement("pi"
  109.                                                 id=0 
  110.                                                 pitag.setAttribute("ID",str(id)) 
  111.                                                 top.appendChild(pitag) 
  112.                                                 for id,a in self.achievements.iteritems(): 
  113.                                                             if a["question"]!=None
  114.                                                                         ac=dom.createElement("achievement"
  115.                                                                         ac.setAttribute("ID",id) 
  116.                                                                         q=dom.createElement("question"
  117.                                                                         text=dom.createTextNode(str(a["question"])) 
  118.                                                                         q.appendChild(text) 
  119.                                                                         ac.appendChild(q) 
  120.                                                                         for answer in a["answers"]: 
  121.                                                                                     ans=dom.createElement("answer"
  122.                                                                                     txt=dom.createTextNode(str(answer)) 
  123.                                                                                     ans.appendChild(txt) 
  124.                                                                                     ac.appendChild(ans) 
  125.                                                             pitag.appendChild(ac) 
  126.                                                 file=open(self.pi,'w'
  127.                                                 dom.writexml(file) 
  128.              
  129.             def LoadPeople(self): 
  130.                         dom=self.Load(self.peoplef,"People"
  131.                         p_tags=dom.getElementsByTagName("person"
  132.                         people={} 
  133.                         for p in p_tags: 
  134.                                     id=p.getAttribute("ID"
  135.                                     ntag=p.getElementsByTagName("name")[0
  136.                                     name=ntag.childNodes[0].data 
  137.                                     atag=p.getElementsByTagName("achievement"
  138.                                     achievements=[] 
  139.                                     for a in atag: 
  140.                                                 if a.childNodes[0].data not in achievements: 
  141.                                                             achievements.append(a.childNodes[0].data) 
  142.                                     people[id]={"name":name,"achievements":achievements} 
  143.                         return people 
  144.  
  145.             def SavePeople(self): 
  146.                         dom=self.Load(self.peoplef,"People"
  147.                         top=dom.documentElement 
  148.                         old_p=self.LoadPeople() 
  149.                         people_tags=top.getElementsByTagName("person"
  150.                         for id,p in self.people.iteritems(): 
  151.                                     if id in old_p.keys(): 
  152.                                                             for pe in people_tags: 
  153.                                                                         if pe.getAttribute("ID")==id: 
  154.                                                                                     for achievement in p["achievements"]: 
  155.                                                                                                 if achievement not in old_p[id]["achievements"]: 
  156.                                                                                                             ac_tag=dom.createElement("achievement"
  157.                                                                                                             ac_text=dom.createTextNode(achievement) 
  158.                                                                                                             ac_tag.appendChild(ac_text) 
  159.                                                                                                             pe.appendChild(ac_tag) 
  160.                                     else
  161.                                                 peep=dom.createElement("person"
  162.                                                 peep.setAttribute("ID",id) 
  163.                                                 n=dom.createElement("name"
  164.                                                 text=dom.createTextNode(str(p["name"])) 
  165.                                                 n.appendChild(text) 
  166.                                                 peep.appendChild(n) 
  167.                                                 for achievement in p["achievements"]: 
  168.                                                             ac=dom.createElement("achievement"
  169.                                                             txt=dom.createTextNode(str(achievement)) 
  170.                                                             ac.appendChild(txt) 
  171.                                                             peep.appendChild(ac) 
  172.                                                 top.appendChild(peep) 
  173.                         file=open(self.peoplef,'w'
  174.                         dom.writexml(file) 
  175.  
  176.  
  177.             def AddAchievement(self,desc,question,answers): 
  178.                         return None 
  179.              
  180.             def UpdateAchievement(self,updated_entry): 
  181.                         return None 
  182.  
  183.             def DeleteAchievement(self,id): 
  184.                         return None 
  185.  
  186.             def GetAchievement(self, id): 
  187.                         if id in self.achievements.keys(): 
  188.                                     return self.achievements[id] 
  189.                         else
  190.                                     return None 
                                  


Jetzt, da Sie über eine Infrastruktur verfügen, machen wir mit den letzten beiden Methoden-Stubs weiter. Diese ermöglichen es uns, Aktivitäten anzupassen.
Da die Dateiverarbeitung an einer anderen Stelle stattfindet, sind die weiteren Schritte relativ einfach:

   
  1.             def AddAchievement(self,desc,question,answers): 
  2.                         ids=[int(i) for i in self.achievements.keys()] 
  3.                         sorted_ids=sorted(ids) 
  4.                         id=sorted_ids[-1]+1 
  5.                         self.achievements[str(id)]={"question":question,"answers":answers,"Description":desc} 
  6.                         self.SavePi() 
  7.              
  8.             def UpdateAchievement(self,updated_entry): 
  9.                         if id in self.achievements.keys(): 
  10.                                     self.achievements[id]=updated_entry 
  11.                         else
  12.                                     print "Achievement not found" 
  13.  
  14.             def DeleteAchievement(self,id): 
  15.                         if id in self.achievements.keys(): 
  16.                                     del self.achievements[id] 
  17.                         else
  18.                                     print "Achievement not found" 

Wir fangen ganz oben an: „Add“ (Erstellen) stellt ganz einfach anhand der höchsten ID fest, welche ID als nächstes kommt. Dazu zieht dieser Befehl ein Verzeichnis aller Aktivitäten-IDs heran, ordnet diese aufsteigend an,
nimmt dann den letzten Eintrag (sorted_ids[-1]) und fügt ihm eine 1 hinzu.
Diesen Eintrag fügen wir nun hinzu und speichern die Datei.
„Update“ (Aktualisieren) ist sogar noch einfacher – dieser Befehl findet einen Eintrag und tauscht ihn mit einer anderen Verzeichnisreferenz aus, die von der Admin-Seite vervollständigt wird.
„Delete“ (Löschen) prüft, ob eine ID vorliegt, und löscht sie.
Jetzt können wir nfc.py schließen und eine Admin-Seite erstellen. Drücken Sie also STRG+X, Y und Eingabe.
Geben Sie anschließend sudo nano admin.py und folgenden Stub ein:

  1. from nfc import NFC 
  2.  
  3. class UI(object): 
  4.             def __init__(self,pi,people): 
  5.                         self.NFC=NFC(pi,people) 
  6.                         self.CRUD={1:self.View,2:self.Create,3:self.Update,4:self.Delete,5:self.Quit} 
  7.  
  8.             def Menu(self): 
  9.                         print "Welcome to xyz admin." 
  10.                         print "1. View Achievements" 
  11.                         print "2. Add Achievements" 
  12.                         print "3. Update Achievements" 
  13.                         print "4. Remove Achievements" 
  14.                         print "5. Quit" 
  15.                         valid=False 
  16.                         while not valid: 
  17.                                     input=raw_input('Enter an option:'
  18.                                     validate=self.ValidateChoice(input) 
  19.                                     if validate == True
  20.                                                 valid=True 
  21.                                     else
  22.                                                 print validate 
  23.                         self.CRUD[int(input)]() 
  24.  
  25.             def View(self): 
  26.                         return None 
  27.  
  28.             def Create(self): 
  29.                         return None 
  30.  
  31.             def Update(self): 
  32.                         return None 
  33.                                                  
  34.             def Delete(self): 
  35.                         return None 
  36.  
  37.             def Quit(self): 
  38.                         return None 
  39.  
  40.             def ValidateChoice(self,item): 
  41.                         inte=self.ValidateInt(item) 
  42.                         if not inte: 
  43.                                     return "Entry not an integer" 
  44.  
  45.                         if int(item) not in self.CRUD.keys(): 
  46.                                     return str(item)+ " not in list" 
  47.                         else
  48.                                     return True 
  49.              
  50.             def ValidateInt(self,item): 
  51.                         try
  52.                                     val=int(item) 
  53.                                     return True 
  54.                         except
  55.                                     return False 
  56.             def ProcessEntry(self,string): 
  57.                         valid=False 
  58.                         while not valid: 
  59.                                     id=raw_input('Please enter a valid ' +string+ ': '
  60.                                     valid=self.ValidateInt(id) 
  61.                                     if not valid: 
  62.                                                 print "Invalid number" 
  63.                         return id 
  64.  
  65. self=UI('pi.xml','people.xml'
  66.  
  67. self.Menu() 
                                  


Wir erstellen nun eine menügesteuerte Benutzerschnittstelle. Diese ist vergleichbar mit automatisierten Telefonansagen wie „Drücken Sie die 1 hierfür, die 2 dafür und die 3, um mit einem Ansprechpartner verbunden zu werden“.
Da wir sie jedoch lesen können, ist es wesentlich einfacher, damit zu arbeiten. Alle Optionen werden im Menü() angezeigt. Hier kann der Benutzer dann seine Auswahl treffen.
Falls der Benutzer eine ungültige Auswahl trifft, wird dies sofort durch die ValidateChoice-Methode gekennzeichnet. Diese Methode überprüft, ob ein Eintrag ein Integer ist und ob sich die ID im CRUD-Verzeichnis wiederfindet.
Das CRUD-Verzeichnis, das wir beim „init“ festgelegt haben (self.CRUD), ist ziemlich speziell, da es nicht über Daten verfügt, sondern jeder ID eine Methode hinzufügt. So werden Switch-Case-Anweisungen in Python ersetzt,
die nicht existieren – in Programmiersprachen wie C, C++, C#, Java und vielen weiteren funktioniert ein Switch-Case wie folgt:

  1. value=user_input; 
  2. switch(value){ 
  3.             case 0
  4.                         DoSomething(); 
  5.                         break 
  6.              
  7.             case 1
  8.                         DoSomethingElse(); 
  9.                         break
  10.              
  11.             default
  12.                         DoSomethingIfAllOtherOptionsArentChosen(); 
  13.                         break
  14.             } 

So kann der Code in viele verschiedene Richtungen ausgelegt werden, je nachdem, welche Auswahl getroffen wird. Das kann Python zwar nicht, aber unser Verzeichnis funktioniert ganz genau so. Sobald wir wissen, dass die Benutzereingabe gültig ist, wird dieses Verzeichnis also aufgerufen.
Die andere Methode, auf die ich bisher noch nicht eingegangen bin – ProcessEntry – wird immer dann aufgerufen, wenn wir sie benötigen. Das ermöglicht es uns, einen Benutzer immer wieder um eine gültige Eingabe zu bitten, bis endlich eine für uns verwertbare Eingabe erfolgt ist.
Diese Methode können wir allerdings nicht in unserem Menü verwenden, da wir nicht nur einen gültigen Integer benötigen, sondern der Eintrag auch in einer bestimmten Liste vorkommen muss, was für spätere Einträge jedoch nicht gilt.
Wenn der Benutzer jetzt jedoch eine Auswahl eingibt, wird das Programm beendet, da die Methoden hier nichts ausrichten können. Lassen Sie sie uns also befüllen:

  1.             def View(self): 
  2.                         input=raw_input('Display all achievements? (y/n)'
  3.                         if input.lower()=='y'
  4.                                     entries=self.NFC.achievements 
  5.                                     for id, a in entries.iteritems(): 
  6.                                                 print "ID: ", id 
  7.                                                 for id, entry in a.iteritems(): 
  8.                                                             print id, ": ", entry 
  9.                         else
  10.                                     id=self.ProcessEntry('Achievement ID'
  11.                                     entry=self.NFC.GetAchievement(id) 
  12.                                     if entry is None
  13.                                                 print "Achievement not found" 
  14.                                     else
  15.                                                 for id, e in entry.iteritems(): 
  16.                                                             print id, " : ", e 
  17.  
  18.  
  19.             def Create(self): 
  20.                         num=int(self.ProcessEntry('number of achievements')) 
  21.                         for i in range(num): 
  22.                                     desc=raw_input('Achievement description:'
  23.                                     question=raw_input('Question:'
  24.                                     vint=False 
  25.                                     ansint=int(self.ProcessEntry('number of answers')) 
  26.                                     answers=[] 
  27.                                     for i in range(ansint): 
  28.                                                 answer=raw_input('Enter answer '+str(i)+':'
  29.                                                 answers.append(answer) 
  30.                                     self.NFC.AddAchievement(desc,question,answers) 

Die Methode „View“ (Prüfen) ruft entweder alle Aktivitäten ab, geht jede davon einzeln durch und zeigt dabei die verschiedenen Werte innerhalb des Verzeichnisses an, oder aber sie lässt den Benutzer eine Aktivität anhand einer ID wählen und zeigt diese an.
„Create“ (Erstellen) fordert erst eine Reihe Aktivitäten mithilfe der ProcessEntry-Methode an. Anschließend muss für jede Aktivität ein Eintrag angegeben werden, bis alle Aktivitäten erstellt worden sind.
Hier haben wir eine Beschreibung in Form einer Art Stub – diese wird üblicherweise unter der API gespeichert, aber wenn Sie sie allein nutzen, dann können Sie auch einfach die xml entsprechend anpassen und die Beschreibung hier speichern.
Weiter geht's:

  1.             def Update(self): 
  2.                         id=self.ProcessEntry('Achievement ID'
  3.                         entry=self.NFC.GetAchievement(id) 
  4.                         new_e={} 
  5.                         if entry is not None
  6.                                     for id in entry.keys(): 
  7.                                                 if id != "answers"
  8.                                                             update=raw_input('Enter update for '+id+': '
  9.                                                             new_e[id]=update 
  10.                                                 else
  11.                                                             answers=[] 
  12.                                                             for a in entry["answers"]: 
  13.                                                                         u=raw_input('Enter update for answer '+a+': '
  14.                                                                         answers.append(u) 
  15.                                                             new_e[id]=answers 
  16.                                     self.NFC.UpdateAchievement(new_e) 
  17.                                     print "Update successful!" 
  18.                         else
  19.                                     print "Update failed" 
  20.                                                  
  21.             def Delete(self): 
  22.                         id=self.ProcessEntry('Achievement ID'
  23.                         entry=self.NFC.GetAchievement(id) 
  24.                         for key, e in entry.iteritems(): 
  25.                                     print key, ":", e 
  26.                         yn=raw_input('Confirm delete? (y/n)'
  27.                         if yn.lower()=='y' or yn.lower()=="yes"
  28.                                     self.NFC.DeleteAchievement(id) 
  29.                         else
  30.                                     return None 

Dieser Abschnitt ist ziemlich selbsterklärend: Unter „Update“ (Aktualisieren) wird ein Eintrag eingegeben, nach dem gesucht werden soll. Die Methode beginnt dann mit der Suche und legt für jeden Eintrag einen neuen Eintrag an.
Wahrscheinlich könnte man auch den vorherigen Eintrag für jeden Punkt ausgeben:

  1. if id != "answer"
  2.             print "previous " +id+ ":", entry[id] 
  3.             update=raw_input('Enter update for '+id+': '

„Delete“ (Löschen) hat eine sehr ähnliche Funktion – die Methode ruft einen Eintrag auf, gibt ihn aus und fordert Sie dann auf, zu bestätigen, dass der Eintrag wirklich gelöscht werden soll.
Dies sind Methoden, die wie benötigen, um eine ganz grundlegende Schnittstelle zu erstellen. Für diese Datei sollten eigentlich nur sehr weniger Anpassungen erforderlich sein, da Aktualisierungen für das Laden
und Speichern von Daten von by nfc.py durchgeführt werden.
Wenn Sie die Datei jetzt schließen und ausführen, sollten Sie über ein praktisches Menü verfügen, mit dem Sie Aktivitäten nach Belieben aktualisieren und anpassen können.

sc6.png

Im nächsten Beitrag bewegen wir uns kurz weg vom Pi und gehen genauer auf das Erstellen einer einfachen Web-API mit Azure ein. Wenn Sie gerne einen anderen Dienst nutzen möchten, dann können Sie diesen Beitrag natürlich einfach überspringen. Das letzte Tutorial sollten Sie trotzdem problemlos umsetzen können.
[Pssst... wenn Ihnen das ewige Copy&Paste zu langweilig ist, dann ist dieses Github-Repository genau das Richtige für Sie. Es ist wahrscheinlich einfacher in der Anwendung, da die Einzüge in Python oft verrutschen, aber trotzdem gilt: Lesen Sie alles aufmerksam, schummeln Sie nicht und überspringen Sie keine Schritte!]

Links zu vorherigen Tutorials: Projektvorstellun, Die Einrichtung der NFC

Hier geht es zum ersten Eintrag „Projektvorstellung“ und zum zweiten Eintrag „Das NXP NFC-Explorer-Board in der Praxis.“

In meinem vorigen Blogeintrag bin ich bereits darauf eingegangen, worum es bei diesem Thema geht und wie sich NXP in Windeseile einrichten lässt.

In diesem Beitrag erläutere ich Ihnen, wie Sie die NFC allgemein und ihren Code klassifizieren können und wie so aus den vielen Einzelteilen – der Datenein- und -ausgabe, dem Auslesen von NFC-Karten etc. – ein großes Ganzes wird.

Wir beginnen mit einem ganz grundlegenden Stub – geben Sie Folgendes im Pi Terminal ein:

sudo nano nfc.py

Geben Sie anschließend den folgenden Code ein – ich erkläre Ihnen, was Sie wo beachten müssen:

import nxppy
import os,json,requests
from xml.dom import minidom

class NFC(object):
  def __init__(self,pifile,peoplefile):
  self.pi=pifile
  self.peoplef=peoplefile


  self.achievements=self.LoadPi()
  self.people=self.LoadPeople()

  def ReadCard(self):
  return None
  def Load(self,file,type):
  if os.path.exists(file):
  source=open(file)
  try:
  dom1=minidom.parse(source)
  except:
  impl=minidom.getDOMImplementation()
  dom1=impl.createDocument(None,type,None)
  return dom1
  else:
  impl=minidom.getDOMImplementation()
  doc=impl.createDocument(None, type,None)
  return doc

  def LoadPi(self):
  return None

  def SavePi(self):
  return None

  def LoadPeople(self):
  return None

  def SavePeople(self):
  return None


  def AddAchievement(self,desc,question,answers):
  return None

  def UpdateAchievement(self,updated_entry):
  return None

  def DeleteAchievement(self,id):
  return None

  def GetAchievement(self, id):
  return None






 

Was haben wir hier also? An erster Stelle kommt „__init__“, unser Initialisierungsbefehl. Dieser wird aufgerufen, wenn eine Kopie dieser Klassifizierung zu einem späteren Zeitpunkt ausgeführt wird. Hier sollten Sie alle Variablen, die zur Klassifizierung gehören, einbeziehen. Führen Sie außerdem die Methoden aus, die von vornherein erforderlich sind.

Der einzige andere Stub, den wir ausfüllen, ist „Load“. Dieser ist eine generische Methode, mit der wir sämtliche erforderlichen xml-Dateien öffnen können – wir verwenden xml, um die Daten für unser System zu speichern.

Die anderen Methoden ermöglichen uns die Erstellung einer Datenklasse, die alle Bereiche abdeckt – so stehen uns Lade- und Speichermethoden für die xml-Ausgabe (Load/SavePi und Load/SavePeople) und auch CRUD-Methoden (Create, Review, Update, Delete, also Erstellen, Prüfen, Aktualisieren und Löschen) für die Variablen innerhalb der Klasse zur Nutzung zu einem späteren Zeitpunkt zur Verfügung.

 

Lassen Sie uns den Stub also Schritt für Schritt befüllen. Los geht es mit Load/SavePi – die Pi Datei befindet sich dort, wo wir Aktivitäten und Informationen zu der Station, an der wir gerade arbeiten, speichern:

 

def LoadPi(self):
  dom=self.Load(self.pi,"piSyst")
  try:
  pi_tag=dom.getElementsByTagName("pi")[0]
  except:
  self.SavePi()
  dom=self.Load(self.pi,"piSyst")
  pi_tag=dom.getElementsByTagName("pi")[0]
  a_tags=pi_tag.getElementsByTagName("achievement")
  achievements={}
  achievements[pi_tag.getAttribute("ID")]={"question":None,"answers":None}
  for a in a_tags:
  id=a.getAttribute("ID")
  qtag=a.getElementsByTagName("question")[0]
  question=qtag.childNodes[0].data
  atag=a.getElementsByTagName("answer")
  answers=[]
  for an in atag:
  answers.append(an.childNodes[0].data)
  achievements[id]={"question":question,"answers":answers}
  return achievements

  def SavePi(self):
  dom=self.Load(self.pi,"piSyst")
  top=dom.documentElement
  old_achievements=self.LoadPi()
  if(len(dom.getElementsByTagName("pi"))==0):
  pi=dom.createElement("pi")
  id=0
  pi.setAttribute("ID",str(id))
  top.appendChild(pi)
  else:
  pitag=dom.getElementsByTagName("pi")[0]
  if old_achievements != self.achievements:
  try:
  os.remove(self.pifile)
  except:
  pass
  dom=self.Load(self.pi,"piSyst")
  pitag=dom.createElement("pi")
  id=0
  pitag.setAttribute("ID",str(id))
  top.appendChild(pitag)
  for id,a in self.achievements.iteritems():
  if a["question"]!=None:
  ac=dom.createElement("achievement")
  ac.setAttribute("ID",id)
  q=dom.createElement("question")
  text=dom.createTextNode(str(a["question"]))
  q.appendChild(text)
  ac.appendChild(q)
  for answer in a["answers"]:
  ans=dom.createElement("answer")
  txt=dom.createTextNode(str(answer))
  ans.appendChild(txt)
  ac.appendChild(ans)
  pitag.appendChild(ac)
  file=open(self.pi,'w')
  dom.writexml(file)






 

Hier kommt eine kompakte Bibliothek namens „minidom“ zum Einsatz – DOM steht hierbei für Document Object Model – die zur Verarbeitung von xml-Dateien dient. Mit der minidom können xmls in DOMs umgewandelt werden, aus denen wir wiederum Daten prüfen und abrufen können.

Beginnend mit dem LoadPi lädt der Algorithmus das DOM aus der Lademethode und versucht, ein Pi Tag aufzurufen – dieses Tag kommt in jedem Dokument vor und sollte daher immer auch das einzige sein.

Wenn das Tag nicht gefunden werden kann, bedeutet das, dass wir diese Station bisher noch nicht verwendet haben. Daher speichert das System das Pi und erstellt uns gleichzeitig ein Pi Tag.

Nach der Bewältigung dieses kleinen Problems machen wir weiter und versuchen nun, Aktivitäten zu suchen – hier ein paar kurze Erläuterungen:

- Jedes Pi mit einer eigenen ID wird auch als eigene Aktivität eingestuft: Diese werden zwar nicht als Aktivitäten aufgezählt, da sie in der Datei selbst keine Fragen und Antworten erfordern, aber das System fügt sie automatisch dem Aktivitätenverzeichnis hinzu.

- Für jedes Pi können Aktivitäten auch direkt vom Admin erstellt werden. Das geht derzeit zwar nur im Frage- und Antwortenformat, allerdings sind immer mehrere Antworten möglich.

Das System ruft jede Frage und jede Antwort einzeln auf und erstellt dazu jeweils einen Eintrag im Aktivitätenverzeichnis. Diese Einträge werden nach ihren eigenständigen IDs sortiert.

Der Einfachheit halber habe ich mich dazu entschlossen, die gesamte Datei zu löschen und neu zu erstellen. So erhalte ich meiner Ansicht nach eine besser aufgebaute Syntax, und um alle Einträge zu aktualisieren, müssen wir sowieso den gesamten Stamm durchgehen.

Jetzt lassen Sie uns zum Laden und Speichern von Benutzern, die ihre NFC-Karten eingelesen haben, übergehen:

         

def LoadPeople(self):
  dom=self.Load(self.peoplef,"People")
  p_tags=dom.getElementsByTagName("person")
  people={}
  for p in p_tags:
  id=p.getAttribute("ID")
  ntag=p.getElementsByTagName("name")[0]
  name=ntag.childNodes[0].data
  atag=p.getElementsByTagName("achievement")
  achievements=[]
  for a in atag:
  if a.childNodes[0].data not in achievements:
  achievements.append(a.childNodes[0].data)
  people[id]={"name":name,"achievements":achievements}
  return people

  def SavePeople(self):
  dom=self.Load(self.peoplef,"People")
  top=dom.documentElement
  old_p=self.LoadPeople()
  people_tags=top.getElementsByTagName("person")
  for id,p in self.people.iteritems():
  if id in old_p.keys():
  for pe in people_tags:
  if pe.getAttribute("ID")==id:
  for achievement in p["achievements"]:
  if achievement not in old_p[id]["achievements"]:
  ac_tag=dom.createElement("achievement")
  ac_text=dom.createTextNode(achievement)
  ac_tag.appendChild(ac_text)
  pe.appendChild(ac_tag)
  else:
  peep=dom.createElement("person")
  peep.setAttribute("ID",id)
  n=dom.createElement("name")
  text=dom.createTextNode(str(p["name"]))
  n.appendChild(text)
  peep.appendChild(n)
  for achievement in p["achievements"]:
  ac=dom.createElement("achievement")
  txt=dom.createTextNode(str(achievement))
  ac.appendChild(txt)
  peep.appendChild(ac)
  top.appendChild(peep)
  file=open(self.peoplef,'w')
  dom.writexml(file)






                       

Die Struktur für Benutzer ist etwas einfacher: Jeder Benutzer wird als <Person ID="NFC_ID"></Person> hinzugefügt und verfügt über <achievement>0</achievement>, das für die bisher gesammelten Aktivitäten-IDs steht.

Da bei der Speichermethode keine Möglichkeit besteht, einen Benutzer zu entfernen oder zu löschen, müssen wir hier nur prüfen, ob ein Benutzer bereits über eine bestimmte ID in seinem Aktivitätenverzeichnis verfügt. Das ist nicht von allerhöchster Bedeutung, da der Lade-Code sowieso nach Duplikaten sucht, aber wir sollten hier einfach nochmal selbst sichergehen.

Jetzt, da wir über all die erforderliche „Infrastruktur“ verfügen, um die Daten aus dem Lesegerät zu speichern und zu laden, können wir die Kartenlesemethode erstellen:

        

def ReadCard(self):
  id=nxppy.rad_mifare()
  if id == None:
  return None
  else:
  if id not in self.people.keys():
  print "new ID :", id
  name=raw_input('Please enter your name:')
  self.people[id]={"name":name,"achievements":[]}
  if id in self.people.keys():
  for aid in self.achievements.keys():
  if aid not in self.people[id]['achievements']:
  if self.achievements[aid]['question']==None:
  self.people[id]['achievements'].append(aid)
  print "Achievement unlocked!"
  else:
  print self.achievements[aid]['question']
  ans=[]
  for a in range(len(self.achievements[aid]['answers'])):
  answer=raw_input('Enter answer:')
  ans.append(answer)
  correct=0
  for an in range(len(ans)):
  found=False
  for answ in self.achievements[aid]['answers']:
  if answ==ans[an]:
  found=True
  break
  if not found:
  print "answer" + str(ans) + " incorrect!"
  else:
  correct+=1
  if correct == len(self.achievements[aid]['answers']):
  print "achievement unlocked!"  
  self.people[id]['achievements'].append(aid)
  self.SavePeople()
  return self.people[id]






 

Hier wird es nun etwas komplexer, da uns jetzt richtige Daten vorliegen.

Als Erstes überprüfen wir, ob sich eine einzulesene Karte in der Nähe des Lesegeräts befindet. Falls nicht, passiert nichts.

Falls ja, und falls sich diese Person nicht in der Liste an Benutzern wiederfindet, die zuvor an dieser Station waren, dann bitten wir sie darum, sich in unsere Datenbank einzutragen.

Falls diese Person zuvor bereits erfasst worden ist, dann schauen wir uns jede einzelne Aktivität an und überprüfen, ob diese Aktivitäten bereits erfasst wurden. Falls nicht, und falls es sich nur um Pi

Aktivitäten handelt, dann fügen Sie diese sofort hinzu und informieren Sie den Benutzer darüber. Falls eine Frage vorliegt, dann bitten wir den Benutzer um die entsprechende Antwort und überprüfen anschließend, ob alle Antworten korrekt sind.

Zum Schluss speichern wir die Datei und fügen den Benutzereintrag wieder in das Verzeichnis ein.

Jetzt können wir diese Klassifizierung also verwenden – die CRUD-Methoden (Erstellen, Prüfen, Aktualisieren und Löschen) nehmen wir uns vor, wenn wir ein Admin-Portal anlegen – außer „Prüfen“, da dieser Teilvorgang auch gut für die NFC-Reader-Datei geeignet wäre:

 

def GetAchievement(self, id):
  if id in self.achievements.keys():
  return self.achievements[id]
  else:
  return None






 

Diese Datei schließen wir nun – geben Sie erst STRG+X und danach Y ein, und drücken Sie auf Eingabe.

Geben Sie jetzt Folgendes im Terminal ein:

sudo nano read.py


Nehmen Sie außerdem folgende Eingaben vor:

from nfc import NFC

self=NFC('pi.xml','people.xml')
person=self.ReadCard()
if person != None:
  print "Hello " + person["name"]
  print "you have collected ",len(person["achievements"])," achievements"  
  for a in person["achievements"]:
  print "ID: ", a
  achievement=self.GetAchievement(a)
  if "Description" in achievement.keys():
  print "Description: ", achievement['Description']






 

 

 

Das ist jetzt wieder etwas komplexer als die vorigen Schritte. Wir haben jetzt unsere eben erstellte Klassifizierung importiert, ausgeführt (self=NFC('pi.xml','people.xml')) und den Benutzer erfasst.

Jetzt prüfen wir, ob hierzu ein Eintrag vorliegt und informieren den Benutzer entsprechend darüber. Beachten Sie, dass es unterself.ReadCard mehrere Anzeigeanweisungen gibt. Diese werden zuvor angezeigt und informieren den Benutzer über die Ergebnisse eines bestimmten Scans.

 

if "Description" in achievement.keys():
  print "Description: ", achievement['Description']






 

Wir haben hier etwas Spielraum für alle Eventualitäten gelassen, damit wir diese Datei später nicht anpassen müssen:

 

sudo python read.py

 

Grund hierfür ist, dass wir bei den Schritten 5 und 6 später eine Beschreibung speichern müssen, die allerdings aus der Web-API und nicht
aus der xml-Datei gezogen wird.

Jetzt können Sie diese Datei schließen (STRG+X, Y und Eingabe) und geben Folgendes ein:

 

sudo python read.py

 

Ziehen Sie dabei Ihre NFC-Karte über das Lesegerät.

 

Jetzt sollte Ihnen Folgendes angezeigt werden:

 

sc3.png

 

Und wenn Sie Ihren Namen eingeben, sollte es dazu zwei Dateien geben – people.xml:

sc3.png

und pi.xml:

sc5.png

 

 

In meinem nächsten Beitrag erstellen wir gemeinsam einen Admin-Bereich, damit wir die verfügbaren Aktivitäten bearbeiten können.