Raspberry Pi Android Projects

Transcription

Raspberry Pi Android Projects
RaspberryPiAndroidProjects
TableofContents
RaspberryPiAndroidProjects
Credits
AbouttheAuthor
AbouttheReviewers
www.PacktPub.com
Supportfiles,eBooks,discountoffers,andmore
Whysubscribe?
FreeaccessforPacktaccountholders
Preface
Whatthisbookcovers
Whatyouneedforthisbook
Whothisbookisfor
Conventions
Readerfeedback
Customersupport
Downloadingtheexamplecode
Downloadingthecolorimagesofthisbook
Errata
Piracy
Questions
1.MakeaRemoteDesktopConnectiontoYourPifromAnywhere
Prerequisites
InstallingLinuxonyourPi
InstallingusingNOOBS
InstallingusingaRaspbianimage
ExtractingtheOSimagetoanSDcard
Makingnecessarychangesinsettings
InstallingnecessarycomponentsinthePiandAndroid
ConnectingthePiandAndroid
WhatifIwanttouseWi-FionthePi?
Connectingfromanywhere
ProblemswithdynamicLANIPaddressesandexternalIPaddresses
Summary
2.ServerManagementwithPi
RemoteconsoletothePifromAndroid
ExchangingfilesbetweenthePiandAndroid
Asimpledatabaseandwebserverimplementation
Connectingthesensor
Installingthedatabase
Installingthewebserver
Simplemanagementofservers
Summary
3.LiveStreamingofaSurveillanceCamerafromthePi
Hardwareandsoftwareconfigurations
StreamingvideotoanAndroiddevice
ManualVLCconfigurations
Thesurveillancemode
AccessingsurveillanceimagesontheWeb
Summary
4.TurnYourPiintoaMediaCenter
InstallingandsettingupamediacenteronPi
StartingKodionboot
ConnectingtothemediacenterviaremotecontrolfromAndroid
Gettingmorefromyourmediacenter
WatchingvideosusingKodionanAndroiddevice
StreamingtheAndroiddisplaytoKodi
InstallingthemediacenterusingNOOBS
Summary
5.MissedCallswithPi
Installingthenecessarycomponents
AddingasensorservicetoBluetoothLowEnergy
ConnectingfromanAndroidapp
SendingtherebootcommandfromyourAndroidphonetothePi
SendingmorecommandsfromyourAndroidphonetothePi
LightingtheLEDs
PlayingsoundsonyourPi
Combiningthecommandsandbeinginformedonincomingcalls
Summary
6.TheVehiclePi
Findingoutthecarlocation
Collectingthecardata
GettingthecardatatothePi
UsingyourAndroiddeviceasanaccesspoint
Analternativetorooting
RootingSamsungGalaxyS2
Enablingtetheringonbeingconnectedtoapowersource
Automaticrestartonpowerconnect
Autotethering
Sendingdatatothecloud
Puttingitalltogether
Sendingmeasurements
Retrievingmeasurements
Summary
Index
RaspberryPiAndroidProjects
RaspberryPiAndroidProjects
Copyright©2015PacktPublishing
Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,
ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthe
publisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyofthe
informationpresented.However,theinformationcontainedinthisbookissoldwithout
warranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,andits
dealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecaused
directlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthe
companiesandproductsmentionedinthisbookbytheappropriateuseofcapitals.
However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:September2015
Productionreference:1210915
PublishedbyPacktPublishingLtd.
LiveryPlace
35LiveryStreet
BirminghamB32PB,UK.
ISBN978-1-78588-702-4
www.packtpub.com
Credits
Author
GökhanKurt
Reviewers
ThusharaJayawardena
WolfPaulus
EricWuehler
CommissioningEditor
NadeemBagban
AcquisitionEditor
VivekAnantharaman
ContentDevelopmentEditor
ArwaManasawala
TechnicalEditor
RahulC.Shah
CopyEditor
SoniaCheema
ProjectCoordinator
ShwetaHBirwatkar
Proofreader
SafisEditing
Indexer
MonicaAjmeraMehta
ProductionCoordinator
ArvindkumarGupta
CoverWork
ArvindkumarGupta
AbouttheAuthor
GökhanKurthasbeentryingtokeepupwiththethelatestdevelopmentsintechnology
andITinhis15-year-longdevelopmentcareer.Forthepast4years,hehasbeenworking
atIFSLabs,oneofthetopinnovationdepartmentsoftheSwedishsoftwareindustry.
Currently,heisinvolvedintheInternetofThingsandhasbeendevelopingprototypeIoT
implementationsusingRaspberryPi.
Hehasamaster’sofsciencedegreefromChalmersUniversityofTechnologyanda
bachelorsdegreefromtheMiddleEastTechnicalUniversity.Youcanconnectwithhimon
Twitter(@KurtGok)andonLinkedIn(http://se.linkedin.com/in/kurtgokhan).
Iwouldliketothankmydearwife,Hediye,forherpatienceduringthewritingofthis
book.Specialthankstomy3-year-oldson,Derin,forprovidingmewiththeintellectual
supportneededforwritingthisbookwithhisLegobuildingskills.Iwouldalsoliketo
thankmy3-month-olddaughter,Eliz,forkeepingmeawakeatnightsothatIwasableto
thinkaboutexcitingprojectstoincludeinthisbook.
AbouttheReviewers
ThusharaJayawardenaisinhisfourteenthyearofworkinginthesoftwaredevelopment
industry.Rightafterhegraduatedfromuniversityin2001,hejoinedtheIFSworld
operations(http://www.ifsworld.com/)developmentcenterinColombo,SriLanka.His
earlyyearswerespentasajuniorSWengineer.HethenmovedintoSWsystemsasa
systemengineer,overseeingmission-criticalproductionsystems.Duringthistime,he
becameaprincipalsystemsengineer,andalsomovedtoSwedenin2007wherehestarted
workingattheheadofficeofIFSinLinköping,Sweden.From2014todate,hehasbeen
workingonproductbenchmarkingforIFS.Hehasmainlyworkedwithtechnologies,such
asOracleRDBMS,J2EEsystems,andJboss/OracleWebLogic.Heisalsoknowledgeable
aboutvariousscriptingtechnologiesandlanguages,suchasPowerShellandVBscripting.
Inrecentyears,he’sbeenactiveinmonitoringtoolswritteninAngularJSandGoogle
graphs.Inthefieldofproductbenchmarking,hehasworkedwithdatascience,especially
generatingsyntheticdataforloadsimulations.Hehasalsospentconsiderabletimeatwork
onperformancetestingtools,suchasHPLoadRunner.
Inhissparetime,apartfromtravellingandenjoyingdifferentcultureswithhisson,
daughter,andwife,hespendstimewithAndroid,GoogleAppEngine,andRaspberryPi
home-brewingprojects.
EricWuehlerlivesinthePacificNorthwestwithhislovelywifeandthreechildren.He
hasbeenworkinginthetechnologyfieldprofessionallyforover20years.Hislikes
tinkeringwithmobilesandothersmalldevices.Heisinvolvedinalargenumberof
projectsinvariousstatesofcompleteness,whicharestrewnaboutthemancave(thisis,
coincidentally,thesameroomandhislovelywifereferstoitas“thebasement”).Hecan
bereachedonlineatericwuehler.com.
www.PacktPub.com
Supportfiles,eBooks,discountoffers,and
more
Forsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.
DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFand
ePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandas
aprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwith
usat<[email protected]>formoredetails.
Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signup
forarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooks
andeBooks.
https://www2.packtpub.com/books/subscription/packtlib
DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigital
booklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.
Whysubscribe?
FullysearchableacrosseverybookpublishedbyPackt
Copyandpaste,print,andbookmarkcontent
Ondemandandaccessibleviaawebbrowser
FreeaccessforPacktaccountholders
IfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccess
PacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsfor
immediateaccess.
Preface
Themostpopulargadgetinthemakercommunity,RaspberryPi,andthemostpopular
smartphoneOS,Android,combinetheirpowersinthisbook,resultinginexciting,useful,
andeasy-to-followprojects.Theprojectscoveredcomeinhandyinyourdailyinteraction
withthePiandcanbehelpfulasbuildingblocksforevenmoreamazingprojects.
Whatthisbookcovers
Chapter1,MakeaRemoteDesktopConnectiontoYourPifromAnywhere,teachesyou
howtomaketheinitialsetuptogetstartedwithyourPiandconnectremotelytothePi
desktopfromanAndroiddevicefromanywhereintheworld.
Chapter2,ServerManagementwithPi,buildsonthepreviouschaptertomanagethePi
andthedifferentserversweinstallonit.Wewillevenintroduceaninteresting,useful
projectonthewaythatmakesuseoftheseservers.
Chapter3,LiveStreamingofaSurveillanceCamerafromthePi,showsyouhowtoturn
yourPiintoawebcamandthenintroducesyoutothetechniquestouseitinsurveillance
mode,whichisaccessiblethroughanAndroiddeviceandtheInternet.
Chapter4,TurnYourPiintoaMediaCenter,showsyouhowyoucanturnyourPiintoa
mediacenterthatiscontrollablefromanAndroiddevice.
Chapter5,MissedCallswithPi,introducesthetechniquesrequiredtoaccesssensorsand
componentsonthePifromAndroidthroughBluetoothandshowshowthePicannotify
youaboutthecallsyoureceiveonyourphone.
Chapter6,TheVehiclePi,helpsyouconnectthePitoyourcarandfollowitfromyour
Androidphone.
Whatyouneedforthisbook
AllthesoftwareusedinthisbookisfreelyavailableontheInternet.YouneedRaspberry
Pi2andanAndroiddevice.Insomechapters,wewillevenuseaUSBWi-Fidongle,
DHT11orDHT22temperaturesensor,jumpercables,anLEDlight,aUSBBluetooth
dongle,Picamera,USBGPSreceiver,andanOBDBluetoothinterface,allofwhichare
availableononlinestores.
Whothisbookisfor
RaspberryPiAndroidProjectstargetsthoseofyouwhowanttocreateengagingand
usefulprojectswiththePi,whicharecontrollablethroughanAndroidphone.Noprior
knowledgeofPiorAndroidisrequired.Attheendofeachchapter,youwillhave
succeededincreatingaprojectthatcanbeuseddaily,andwillbeequippedwithskillsthat
couldhelpyoudevelopevenmoreexcitingprojectsinthefuture.Theprojectscoveredin
thisbookwillcontainsomeminorprogrammingstepsandthesestepswillbedescribedin
detailevenforthemostinexperiencedreaders.
Conventions
Inthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkinds
ofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheir
meaning.
Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,
pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“The
nextstepistoinstallacomponentcalledx11vnc.”
Ablockofcodeissetasfollows:
network={
ssid="THEIDOFTHENETWORKYOUWANTTOCONNECT"
psk="PASSWORDOFYOURWIFI"
}
Anycommand-lineinputoroutputiswrittenasfollows:
sudoapt-getinstallapache2
sudoapt-getinstallphp5libapache2-mod-php5
sudoapt-getinstalllibapache2-mod-auth-mysqlphp5-mysql
Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,
forexample,inmenusordialogboxes,appearinthetextlikethis:“Initiatetheconnection
bypressingtheConnectbutton,andyoushouldnowbeabletoseethePidesktoponyour
Androiddevice.”
Note
Warningsorimportantnotesappearinaboxlikethis.
Tip
Tipsandtricksappearlikethis.
Readerfeedback
Feedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthis
book—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsus
developtitlesthatyouwillreallygetthemostoutof.
Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthe
book’stitleinthesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingor
contributingtoabook,seeourauthorguideatwww.packtpub.com/authors.
Customersupport
NowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelp
youtogetthemostfromyourpurchase.
Downloadingtheexamplecode
Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.com
forallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbook
elsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilesemaileddirectlytoyou.Youcanalsodownloadthecodebundleofthisbookfrom
https://github.com/kurtng/Raspberry-Pi-Android-Projects.
Downloadingthecolorimagesofthisbook
WealsoprovideyouwithaPDFfilethathascolorimagesofthescreenshots/diagrams
usedinthisbook.Thecolorimageswillhelpyoubetterunderstandthechangesinthe
output.Youcandownloadthisfilefrom
https://www.packtpub.com/sites/default/files/downloads/Raspberry_Pi_Android_Projects_Colore
Errata
Althoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdo
happen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthe
code—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveother
readersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufind
anyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,
selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthe
detailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedand
theerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataunderthe
Erratasectionofthattitle.
Toviewthepreviouslysubmittederrata,goto
https://www.packtpub.com/books/content/supportandenterthenameofthebookinthe
searchfield.TherequiredinformationwillappearundertheErratasection.
Piracy
PiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.At
Packt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucome
acrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswith
thelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<[email protected]>withalinktothesuspectedpirated
material.
Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluable
content.
Questions
Ifyouhaveaproblemwithanyaspectofthisbook,youcancontactusat
<[email protected]>,andwewilldoourbesttoaddresstheproblem.
Chapter1.MakeaRemoteDesktop
ConnectiontoYourPifromAnywhere
Inthisproject,wewillmakeagentleintroductiontobothPiandAndroidplatformsto
warmusup.ManyusersofthePifacesimilarproblemswhentheywishtoadministerit.
YouhavetobenearyourPiandconnectascreenandakeyboardtoit.Wewillsolvethis
everydayproblembyremotelyconnectingtoourPidesktopinterface.Thechaptercovers
followingtopics:
Prerequisites
InstallingLinuxinyourPi
Makingnecessarychangesinsettings
InstallingnecessarycomponentsinthePiandAndroid
ConnectingthePiandAndroid
Prerequisites
Thefollowingitemsareusedthroughoutthischapterandwillbeneededtocompletethe
project:
RaspberryPi2ModelB:ThisisthelatestadditiontotheRaspberryPifamily.Ithas
replacedthepreviousPi1ModelB+.Thepreviousmodelshouldworkfineforthe
purposeoftheprojectscoveredinthisbook.
MicroSDcard:TheRaspberryPiFoundationrecommendsusingan8GBclass6
microSDcard.
Androiddevice:Thedeviceshouldhaveatleasta1.5orhigherAndroidversion,
whichisrequiredbytheappusedinthischapter.Insomeoftheexcitingprojectsthat
follow,wewillneedAndroid4.3orlaterversions.
HDMIcable:ThiswillbeusedtoconnectthePitoascreenforinitialsetup.
Ethernetcable:Thiswillbeusedfornetworkconnections.
Computer:ThiswillbeusedtocopytheRaspbianOSontothemicroSDcard.
USBmouse:Thiswillbeusedduringinitialsetup.
ThefollowingimageshowstheRaspberryPi2ModelB:
RaspberryPi2ModelB
InstallingLinuxonyourPi
WewilluseRaspbianastheoperatingsystemonourPi.Mychoiceissolelybasedonthe
factthatitisrecommendedbytheRaspberryPiFoundation.ItisbasedontheDebian
versionofLinuxandoptimizedforRaspberryPihardware.Apartfrombeingthemost
usedoperatingsystemforRaspberryPi,itcontainsalmost35,000packages,suchas
games,mailservers,officesuite,internetbrowsersandsoon.Atthetimeofwritingthis
book,thelatestreleasewasdatedMay5,2015.
TherearetwomainwaysofinstallingRaspbian.YoucaneitherusetheOSimageasa
wholeoryoucanbeginwithaneasy-to-usetool-operatingsystembundlecalledNOOBS.
Wewillcoverbothcaseshere.
Note
ThereareSDcardsforsalewithNOOBSorRaspbianalreadyinstalled.Itmightbeagood
ideatogetoneoftheseandskiptheOSinstallationpartofthischapter.
However,beforewebegin,wemightneedtoformatourSDcardaspreviousOS
installationsmaycorruptthecard.You’llnoticethisifonlyafractionoffreespaceonthe
cardisshowntobeavailableeventhoughyouhaveformattedthecardusingthe
formattingutilityprovidedbyyourcomputer’sOS.ThetoolwewilluseiscalledtheSD
FormatterandisavailableforMacandWindowsfromSDAssociationat
https://www.sdcard.org/downloads/formatter_4/index.html.Installandstartit.Youwill
seethefollowinginterfaceaskingyoutoselecttheSDcardlocation:
TheSDFormatterinterface
InstallingusingNOOBS
ThelatestversionofNOOBScanbefoundat
http://downloads.raspberrypi.org/NOOBS_latest.Downloadandextractthecontentsonto
theSDcard.AttachthecardtoyourPiandconnectittoascreenusinganHDMIcable.
DonotforgettoconnecttheUSBmouse.WhenthePiisattachedtoapowersource,you
willbepresentedwithalistofchoicesyoucanmake.ChecktheRaspbianinstallation
optiononthelist,andthenclickonInstall.ThiswillinstallRaspbianonyourSDcardand
restartthePi.
InstallingusingaRaspbianimage
ThelatestversionoftheRaspbianOScanbefoundat
http://downloads.raspberrypi.org/raspbian_latest.TheZIPfileisalmost1GBinsizeand
containsasinglefilewithan.imgextension,whichis3.2GBinsize.Unzipthecontents
andfollowthestepsinthenextsectiontoextractittoasuitablemicroSDcard.
ExtractingtheOSimagetoanSDcard
Toextractanimagefile,weneedadiskimagingutilityandwewilluseafreelyavailable
onecalledWin32DiskImageronWindows.Itcanbedownloadedat
http://sourceforge.net/projects/win32diskimager/.OnMacOS,thereisasimilartoolcalled
ApplePiBakeravailableathttp://www.tweaking4all.com/hardware/raspberry-pi/macosxapple-pi-baker/.Downloadandinstallitontoyourcomputer.Theinstallationwillcontain
anexecutablefile,Win32DiskImager,whichyoushouldstartintheadministratormodeby
rightclickingonitandselectingRunasadministrator.
IntheWin32DiskImagerwindow,youshouldchoosetheimagefileyou’veextracted
andthedriveforSDcardsimilartowhatisshowninthefollowingscreenshot:
TheWin32DiskImagerwindow
ClickingontheWritebuttonwillstarttheprocessandyourSDcardwillbereadytobe
insertedintothePi.
Makingnecessarychangesinsettings
WhenthePiisstillpluggedintoascreenwithHDMI,connectittoanetworkusing
Ethernet.ThefirsttimethePistarts,youwillbepresentedwithasettingsutilityasshown
inthefollowingscreenshot:
RaspberryPiSoftwareConfigurationTool
YoucanoptionallyselectthefirstoptioninthelisttoExpandFilesystem.Selectthethird
optionaswelltoEnableBoottoDesktop.
Inthefollowingmenu,selecttheseconditeminthelistwhichisDesktopLoginasuser
‘pi’atthegraphicaldesktop.Then,choose<Finish>andselectYestorebootthedevice.
Choosedesktopstartupintheconfigurationtool
Afterreboot,youwillbepresentedwiththeRaspbian’sdefaultdesktopmanager
environmentcalledLXDE.
InstallingnecessarycomponentsinthePi
andAndroid
AsthefollowingscreenshotshowstheLXDEdesktopmanagercomeswithaninitialsetup
andafewpreinstalledprograms:
TheLXDEdesktopmanagementenvironment
Byclickingonthescreenimageonthetabbarlocatedatthetop,youwillbeabletoopen
aterminalscreenthatwewillusetosendcommandstothePi.
Thenextstepistoinstallacomponentcalledx11vnc.ThisisaVNCserverforX,the
windowmanagementcomponentofLinux.Issuethefollowingcommandontheterminal:
sudoapt-getinstallx11vnc
Thiswilldownloadandinstallx11vnctothePi.Wecanevensetapasswordtobeusedby
VNCclientsthatwillremotedesktoptothisPiusingthefollowingcommandandprovide
apasswordtobeusedlateron:
x11vnc–storepasswd
Next,wecangetthex11vncserverrunningwheneverthePiisrebootedandtheLXDE
desktopmanagerstarts.Thiscanbedonethroughthefollowingsteps:
1. Gointothe.configdirectoryonthePiuser’shomedirectorylocatedat/home/pi:
cd/home/pi/.config
2. Makeasubdirectoryherenamedautostart:
mkdirautostart
3. Gointotheautostartdirectory:
cdautostart
4. Starteditingafilenamedx11vnc.desktop.Asaterminaleditor,Iamusingnano,
whichistheeasiestonetouseonthePifornoviceusers,buttherearemoreexciting
alternatives,suchasvi:
nanox11vnc.desktop
Addthefollowingcontentintothisfile:
[DesktopEntry]
Encoding=UTF-8
Type=Application
Name=X11VNC
Comment=
Exec=x11vnc-forever-usepw-display:0-ultrafilexfer
StartupNotify=false
Terminal=false
Hidden=false
5. Saveandexitusing(Ctrl+X,Y,Enter)inorderifyouareusingnanoastheeditorof
yourchoice.
6. NowyoushouldrebootthePitogettheserverrunningusingthefollowing
command:
sudoreboot
Afterrebootingusingthesudorebootcommand,wecannowfindoutwhatIP
addressourPihasbeengivenintheterminalwindowbyissuingtheifconfig
command.TheIPaddressassignedtoyourPiistobefoundundertheeth0entryand
isgivenaftertheinetaddrkeyword.Writethisaddressdown:
Exampleoutputfromtheifconfigcommand
7. ThenextstepistodownloadaVNCclienttoyourAndroiddevice.
Inthisproject,wewilluseafreelyavailableclientforAndroid,namely
androidVNCorasitisnamedinthePlayStore—VNCViewerforAndroidby
androidVNCteam+antlersoft.Thelatestversioninuseatthewritingofthisbook
was0.5.0.
Note
NotethatinordertobeabletoconnectyourAndroidVNCclienttothePi,boththe
PiandtheAndroiddeviceshouldbeconnectedtothesamenetwork—Android
throughWi-Fi,andPithroughitsEthernetport.
ConnectingthePiandAndroid
InstallandopenandroidVNConyourdevice.Youwillbepresentedwithafirstactivity
userinterfaceaskingforthedetailsoftheconnection.Here,youshouldprovide
Nicknamefortheconnection,Passwordyouenterwhenyourunthex11vnc–
storepasswdcommand,andtheIPAddressofthePithatyoufoundoutusingthe
ifconfigcommand.InitiatetheconnectionbypressingtheConnectbutton,andyou
shouldnowbeabletoseethePidesktoponyourAndroiddevice.
InandroidVNC,youshouldbeabletomovethemousepointerbyclickingonthescreen
andundertheoptionsmenuintheandroidVNCapp,youwillfindouthowtosendtext
andkeystothePiwiththehelpofEnterandBackspace.
Note
YoumayevenfinditconvenienttoconnecttothePifromanothercomputer.Irecommend
usingRealVNCforthispurpose,whichisavailableonWindows,Linux,andMacOS.
WhatifIwanttouseWi-FionthePi?
InordertouseaWi-FidongleonthePi,firstofall,openthewpa_supplicant
configurationfileusingthenanoeditorwiththefollowingcommand:
sudonano/etc/wpa_supplicant/wpa_supplicant.conf
Addthefollowingtotheendofthisfile:
network={
ssid="THEIDOFTHENETWORKYOUWANTTOCONNECT"
psk="PASSWORDOFYOURWIFI"
}
Note
IassumethatyouhavesetupyourwirelesshomenetworktouseWPA-PSKasthe
authenticationmechanism.Ifyouhaveanothermechanism,youshouldrefertothe
wpa_supplicantdocumentation.LXDEprovidesevenbetterwaystoconnecttoWi-Fi
networksthroughaGUI.Itcanbefoundontheupper-rightcornerofthedesktop
environmentonthePi.
Connectingfromanywhere
Now,wehaveconnectedtothePifromourdevice,whichweneedtoconnecttothesame
networkasthePi.However,mostofuswouldliketoconnecttothePifromaroundthe
worldaswell.Todothis,firstofall,weneedtonowtheIPaddressofthehomenetwork
assignedtousbyournetworkprovider.Bygoingtohttp://whatismyipaddress.comURL,
wecanfigureoutwhatourhomenetwork’sIPaddressis.Thenextstepistologintoour
routerandopenuprequeststothePifromaroundtheworld.Forthispurpose,wewilluse
afunctionalityfoundonmostmodernrouterscalledportforwarding.
Note
Beawareoftheriskscontainedinportforwarding.YouareopeningupaccesstoyourPi
fromallaroundtheworld,eventomalicioususers.Istronglyrecommendthatyouchange
thedefaultpasswordoftheuserpibeforeperformingthisstep.Youcanchangepasswords
usingthepasswdcommand.
Byloggingontotherouter’smanagementportalandnavigatingtothePortForwarding
tab,wecanopenuprequeststothePi’sinternalnetworkIPaddress,whichwehave
figuredoutpreviously,andthedefaultportoftheVNCserver,whichis5900.Now,we
canprovideourexternalIPaddresstoandroidVNCfromanywherearoundtheworld
insteadofaninternalIPaddressthatworksonlyifweareonthesamenetworkasthePi.
PortForwardingsettingsonNetgearrouteradministrationpage
Note
Refertoyourrouter’susermanualtoseehowtochangethePortForwardingsettings.
MostroutersrequireyoutoconnectthroughtheEthernetportinordertoaccessthe
managementportalinsteadofWi-Fi.
ProblemswithdynamicLANIPaddresses
andexternalIPaddresses
Thereisoneminorproblemwiththissetup.ThePimightgetanewLANIPaddresseach
timeyourestartit,makingthePortForwardingsettinguseless.Toavoidthis,most
routersprovidetheAddressReservationsetting.Youcantellmostroutersthateachtime
adevicewithauniqueMACaddressisconnected,itshouldgetthesameIPaddress.
AnotherproblemisthatyourInternetServiceProvider(ISP)mightassignnewIP
addressestoyoueachtimeyourestartyourrouterorforanyotherreason.Youcanusea
dynamicDNSservice,suchasDynDNS,toavoidsuchproblems.Mostroutersarecapable
ofusingdynamicDNSservices.Alternatively,youcangetastaticIPaddressby
contactingyourISP.
Summary
Inthisproject,weinstalledRaspbian,warmedupwiththePi,enabledthedesktop
environmentonit,andconnectedtothePiusinganAndroiddevice.
Inthenextchapter,wewillaccesstheconsoleofthePidirectlyandeventransferfilesto
andfromitusingFTPfromourAndroiddevices.
Chapter2.ServerManagementwithPi
Inthefirsthalfofthisproject,wewillmovefromadesktop-basedconsoletoatext-based
onethatgivesmorepowertotheuserandletsyouperformmoreadvancedtaskscompared
tothedesktop.WewillaccessthePi’sLinuxconsolefromanAndroiddeviceandcontrol
itremotely.Inthesecondhalf,wewillsendandreceivefilesbetweenthePiandAndroid
throughFTP.WewillevencombinethetwopartsbymanagingournewlyinstalledFTP
serverremotelyusingthetext-basedconsole.Inthischapter,wewilleveninstalldatabase
andwebserversontothePitoshowhowtomanagethemlateron.Tomakeitevenmore
fun,wewillimplementasimplebutusefulminiprojectthatmakesuseofbothweband
databaseservers.Thefollowingtopicswillbecovered:
RemoteconsoletothePifromAndroid
ExchangingfilesbetweenthePiandAndroid
Asimpledatabaseandwebserverimplementation
Simplemanagementofservers
RemoteconsoletothePifromAndroid
TheadministratorsofLinuxandUnixcomputershavebeenusingtext-basedcommandlineinterfacescalledshellformanyyearstomanageandadministertheirservers.Asthe
Pi’sOS,Raspbian,isaLinuxvariant,themostnaturalwaytoaccessandissuecommands
orcheckthestatusofrunningprograms,services,anddifferentserversonthePiisagain
byissuingcommandsonthistext-basedshell.Therearedifferentshellimplementations
buttheonethatisusedonRaspbianbydefaultisbash.Themostwell-knownwayof
accessingshellremotelyonaLinuxserveristhroughtheSecureShellprotocolknown,in
general,asSSH.
Note
SecureShell(SSH)isanencryptednetworkprotocolusedtosendshellcommandstoa
remotemachineinasecureway.SSHdoestwothingsforyou.Itenables,through
differenttools,suchastheoneswewillpresenttoyouinamoment,youtosend
commandstotheremotemachineanditdoesthisusingasecurechannelestablishedover
aninsecurenetwork.
ForSSHtowork,thereshouldbeanSSHserveralreadyrunningthatcanacceptand
respondtoSSHclientrequests.OnRaspberryPi,thisfeatureisenabledbydefault.Ifby
anymeans,itisdisabled,youcanenableitusingthePiconfigurationprogrambyissuing
thefollowingcommand:
sudoraspi-config
Then,navigatetosshandhitEnter,andthenselectEnableordisablesshserver.
Ontheclientside,andasweareusingAndroidasourclientthroughoutthisbook,wewill
downloadanappcalledConnectBot.ItisoneofthemostpopularSSHclientsonAndroid
andthelatestversionasoftodayis1.8.4.Downloadittoyourdeviceandopenit.
YouwillneedtoprovidetheusernameandIPaddressthatwefoundoutintheprevious
chapter.WedonotneedtoprovidetheportasConnectBotwillusethedefaultportfor
SSHinthiscase.ClickonYesifyouareaskedtocontinuewiththeconnectionbecauseof
problemswiththeauthenticityofthehost.Youareaskedthisquestionbecauseyouare
connectingtothePiforthefirsttimethrougharemoteSSH.
Notethatinthefollowingscreenshot,IhaveprovidedtheinternalIPaddressofmyhome
network.YoumightwanttouseanexternalIPaddressandconnecttothePifromoutside
yourhomenetwork.Forthispurpose,you’llneedtoaddthestandardFTPports21and20
toyourportforwardingsettingsaswell.ThesameappliestotheSSHprotocol,whichhas
adefaultportnumberof22.
Note
Aswehavediscussedearlier,thereisasecurityriskinopeningportsthiswayandalso
keepingthedefaultpasswordfortheuserpionthePi.
ThefollowingscreenshotillustratesconnectiondetailsonConnectBot:
ConnectiondetailsonConnectBot
Now,providethedefaultpasswordforthepiaccount,whichisraspberry,ortheoneyou
havechangeditto.Afterthisstep,youwillbeconnectedtothePiremotelyusingSSH,as
seeninthefollowingscreenshot:
ThepromptprovidedbyConnectBot
YouarenowreadytoissuecommandsonyourPiandcheckthestatusofdifferent
services.Thisconnectionwillbesavedwithallitsproperties.Nexttimeyouwanttolog
in,youwillnotneedtoprovideanaddress,username,andpasswordinformation.
Note
OnaMacorLinux,youcanusethesshcommandinstalledonyoursystembydefault.On
Windows,youcandownloadPuTTYtoissuethesamecommandsastheonesin
ConnectBot.
ExchangingfilesbetweenthePiand
Android
Inthesecondpartofthischapter,wewillusethePiasanFTPservertosharefiles
betweenourAndroiddevicesorsendfilestothePitoviewthemonalargerscreenthat
youconnecttothePiHDMIport.TheFTPserverwewilluseisvsftpd.Itisalightweight
FTPserverusedinmanysmallprojects.ToinstallitonourPi,weusethefollowing
command:
sudoapt-getinstallvsftpd
TheprecedingcommandwillevenstarttheFTPservice.
However,weshouldmakesomechangesintheconfigurationoftheFTPservertouseit
effectively.Forthispurpose,weneedtoedittheFTPserverconfigurationfileusingthis
command:
sudonano/etc/vsftpd.conf
Findthetwolinescontaining#local_enable=YESand#write_enable=YESandremove
the#commentsignatthebeginningoftheselinesbeforeyousaveandexit.These
changeswillenabletheuserpitologinandbeabletosendfilestothePi.Torestartthe
FTPserver,issuethiscommand:
sudoservicevsftpdrestart
Now,weneedtoinstallanFTPclientonAndroid.Forthispurpose,wewilluseAndFTP.
Itisenoughtousethefreeversionforourproject.Weseethefollowinginitialviewonthe
Androiddeviceafteropeningit:
AninitialviewoftheAndFTPclient
Pressingtheplusbuttonwilltakeyoutothefollowingview,whereyouwillbeaskedfor
connectionproperties:
ConnectionpropertiesonAndFTP
ProvidetheIPaddressofthePiyoufoundoutinthefirstchapter,piasusername,and
raspberryasthepasswordortheoneyouhavechangedto.Then,scrolldowntotheend
oftheviewandpresstheSavebutton.Thiswillsavetheconnectionpropertiesandsend
youbacktothemainview:
ThelistofconnectionsinAndFTP
Clickingonthenewlycreatedconnection,shownasabluefolder,willinitiatetheFTP
connectiontothePiandlogtheuserpiin.Thiswillgetyouintothehomedirectoryforthe
piuser,asshowninthefollowingscreenshot:
Thehomedirectoryofuserpi
NowyouwillbeabletouploadfilesfromyourAndroiddevicetothePibypressingthe
mobilephone-likeiconinAndFTPandchoosingafiletouploadafterwards.Youcanset
upAndFTPfromanotherAndroiddeviceonthesamenetworkorevenanothercomputer
usingabuilt-inFTPclient,anddownloadthenewlyuploadedfiletoviewit;thisway,you
havesharedyourfirstfilebetweendifferentAndroidclientsusingRaspberryPiasanFTP
server.
Asimpledatabaseandwebserver
implementation
Next,we’lltakeourprojectonestepfurtherandinstallbothadatabaseandwebserver,
whichwecanadministerlateronusingConnectBot.Wewillevenmakeitmorefunby
implementingarealprojectthatmakesuseoftheseservers.Thebestcandidateforthis
purposeisasensormeasurementscenario.Wewillconnectatemperature/humiditysensor
toourPiandsavethemeasurementsintoadatabasethatwewillinstallonthePi,whicha
webserverwillmakeavailabletoclients.Wecanlateronmanagetheseserversremotely,
whichisthemainobjectiveinthischapter.
Connectingthesensor
Forthepurposeofthisproject,wewilluseasensor,DHT11,whichmeasuresboth
temperatureandhumidity,butforthesakeofeasierconnections,wewilluseanoff-theshelfmodulecalledKeyesDHT11orDHT11forshort,whichcontainsthesesensors.
Tip
ThereisevenanimprovedversionofDHT11,whichisDHT22.Itcostsalittlebitmore
buthasmoreaccuratesensorsonit.
Usingthissensormoduleinsteadofthesensorsitselfwillenableustoconnectthesensors
tothePiusingonlythreejumperwiresandwithoutabreadboardorresistor.Thereis
anotheradvantageofusingthismoduleinsteadofthesensors:thesensorsprovideanalog
datathatthePicannothandle.PiiscapableofhandlingdigitalinformationonitsGPIO
ports.TheDHT11moduledoestheconversionforus.Thefollowingimageillustratesthe
DHT11sensormodulealongwithadescriptionofthepinsassociatedwithit:
TheDHT11sensormodule
ThefollowingimageillustratestheKeyesDHT11sensormodule:
TheKeyesDHT11sensormodule
Now,connecttheGNDoutputfromthesensormoduletoPi’sGPIOGround,5Voutputto
Pi’s5Vpin,andDATAtoPi’sGPIO-4pin.Thefollowingdiagramshowsthelayoutof
Pi’sGPIOpinsandtheirnames:
RaspberryPiGPIOpinlayout
Thenextstepistoreadthevaluesthesesensorsprovide.Forthispurpose,wewillusea
widelyusedlibraryfromAdafruit,whichisspeciallydesignedforthesekindsofsensors
developedinthePythonprogramminglanguage.Beforewecanuseit,weneedtoinstall
somesoftwarecomponentstoourRaspberryPi.
Firstly,weneedtoupdateourPiandinstallsomedependenciesusingthesecommands:
sudoapt-getupdate
sudoapt-getinstallbuild-essentialpython-dev
ThesensorlibraryitselfisonGitHubandwewilldownloaditfromthereontoourPi
usingthefollowingcommand:
gitclonehttps://github.com/adafruit/Adafruit_Python_DHT.git
Thiscommanddownloadsthelibraryandsavesitinasubdirectory.Now,gointothis
subdirectoryusingthefollowingcommand:
cdAdafruit_Python_DHT
Next,youneedtoactuallyinstallthesensorlibraryusingthefollowingcommand:
sudopythonsetup.pyinstall
Here,weusethestandardPythonthird-partymoduleinstallfunctionality,whichinstalls
theAdafruitlibrarygloballyontoyoursystematthestandardPythonlibraryinstall
location,/usr/local/lib/python2.7/dist-packages/.Thisiswhyweneedsuperuser
privileges,whichwecangetusingsudocommand.
Nowwearereadytobeginreadingmeasurementsfromthesensorusingtheexamplecode
thatwedownloadedtogetherwiththelibrary.Assumingthatyouarestillinthe
Adafruit_Python_DHTdirectory,thefollowingcommanddoesthejob:
sudo./examples/AdafruitDHT.py114
Inthiscommand,11isthedescriptorusedtoidentifyDHT11sensorand4denotesthe
GPIOpin4.Youshouldnowgetanoutputthatlookslikethis:
Temp=25.0*CHumidity=36.0%
Installingthedatabase
AfterverifyingthatthesensorandconnectionstothePiwork,wewillsavethe
measurementsinadatabase.ThedatabasewewilluseisMySQL.Usethefollowing
commandtoinstallMySQLtothePi:
sudoapt-getinstallmysql-serverpython-mysqldb
Duringtheinstallation,youwillbeaskedtosetapasswordfortheadministratoraccount
root.Iwillsetadminasthepasswordandrefertoitintheupcomingcode.Thefollowing
commandtakesyouintotheMySQLshellwhereyoucanissueSQLcommands,suchas
insertingdataintoadatabaseorqueryingdataalreadyinthedatabase.Youshouldprovide
thepasswordyouhavesetwhenyou’reaskedforit:
mysql-uroot-p
YoucanexitfromtheMySQLshellanytimeusingtheexitcommand.
ThenextstepintheMySQLshellistocreateadatabaseanduseitforanyfurtherSQL
statementthatfollow:
mysql>CREATEDATABASEmeasurements;
mysql>USEmeasurements;
ThefollowingSQLstatementwillcreateatableinthisnewlycreateddatabasethatwe
willusetosavesensormeasurements:
mysql>CREATETABLEmeasurements(ttimeDATETIME,temperatureNUMERIC(4,1),
humidityNUMERIC(4,1));
ThenextstepistoimplementaPythonscriptthatreadsfromoursensorandsavesittothe
database.Putthefollowingcodeinafilewiththenamesense.pyunderthehomedirectory
usingthepreviouslydiscussednanocommand.Youcanusethecdcommandwithout
parameterstogobacktothehomedirectoryfromanyplaceinthepidirectorystructure.
Noteanimportantfactthatthefileshouldnotcontainanyemptyprecedinglines,which
meansthatthelinereferringtothePythoncommandshouldbethefirstlineinthefile.
Thefollowingcodeformsthecontentofoursense.pyfile:
#!/usr/bin/python
importsys
importAdafruit_DHT
importMySQLdb
humidity,temperature=Adafruit_DHT.read_retry(Adafruit_DHT.DHT11,4)
#temperature=temperature*1.8+32#fahrenheit
printstr(temperature)+""+str(humidity)
ifhumidityisnotNoneandtemperatureisnotNone:
db=MySQLdb.connect("localhost","root","admin","measurements")
curs=db.cursor()
try:
sqlline="insertintomeasurementsvalues(NOW(),{0:0.1f},
{1:0.1f});".format(temperature,humidity)
curs.execute(sqlline)
curs.execute("DELETEFROMmeasurementsWHEREttime<NOW()-
INTERVAL180DAY;")
db.commit()
print"Datacommitted"
exceptMySQLdb.Errorase:
print"Error:thedatabaseisbeingrolledback"+str(e)
db.rollback()
else:
print"Failedtogetreading.Tryagain!"
Note
YoushouldchangethepasswordparameterintheMySQLdb.connectmethodcalltothe
oneyouhaveassignedtotherootuserontheMySQLserver.Youshouldevenconsider
creatinganewuserwithaccesstojustthemeasurementstableforsecurityreasons,asthe
rootuserhasfullaccesstothedatabase.RefertotheMySQLdocumentationforthis
purpose.
Thenextstepistochangethefilepropertiesandmakeitanexecutablefilewiththe
followingcommand:
chmod+xsense.py
Notethatthisscriptsavesonlyasinglemeasurement.Weneedtoscheduletherunningof
thisscript.Forthispurpose,wewilluseabuilt-inLinuxutilitycalledcron,whichallows
taskstobeautomaticallyruninthebackgroundatregularintervalsbythecrondaemon.
crontab,alsoknownasCRONTABle,isafilethatcontainsthescheduleofcronentries
toberunatspecifiedtimes.Byrunningthefollowingcommand,wecaneditthistable:
crontab–e
Addthefollowinglinetothisfileandsaveit.Thiswillmakethecrondeamonrunour
scriptonceeveryfiveminutes:
*/5****sudo/home/pi/sense.py
Installingthewebserver
Now,wewillsaveourmeasurementsintothedatabase.Thenextstepistoviewthemina
webbrowserusingawebserver.Forthispurpose,wewilluseApacheasthewebserver
andPHPastheprogramminglanguage.ToinstallApacheandthepackagesrequiredfor
ourpurpose,runthefollowingcommands:
sudoapt-getinstallapache2
sudoapt-getinstallphp5libapache2-mod-php5
sudoapt-getinstalllibapache2-mod-auth-mysqlphp5-mysql
Then,changeyourdirectorytothewebserver’sdefaultdirectory:
cd/var/www
Here,wewillcreateafilethatwillbeaccessedbyusersthroughthewebserverwehave
installed.Thefileisexecutedbythewebserverandtheresultofthisexecutionissentto
theclientsconnected.Wewillnameitindex.php:
sudonanoindex.php
Thecontentsshouldlooklikethefollowingcode.Here,youshouldagainchangethe
passwordfortheMySQLuserroottotheoneyouhavechoseninthecalltothenew
mysqliconstructormethod:
<?php
//Createconnection
$conn=newmysqli("localhost","root","admin","measurements");
//Checkconnection
if($conn->connect_error){
die("Connectionfailed:".$conn->connect_error);
}
$sql="SELECTttime,temperature,humidityFROMmeasurementsWHEREttime>
NOW()-INTERVAL3DAY;";
$result=$conn->query($sql);
?>
<html>
<head>
<!--Loadc3.css-->
<linkhref="https://rawgit.com/masayuki0812/c3/master/c3.min.css"
rel="stylesheet"type="text/css">
<!--Loadd3.jsandc3.js-->
<scriptsrc="https://rawgit.com/mbostock/d3/master/d3.min.js"charset="utf8"></script>
<scriptsrc="https://rawgit.com/masayuki0812/c3/master/c3.min.js"></scrip>
</head>
<body>
<divid="chart"></div>
<script>
<?php
if($result->num_rows>0){
?>
varjson=[
<?php
while($row=$result->fetch_assoc()){
?>{ttime:'<?=$row["ttime"]?>',temperature:<?=$row["temperature"]?>
,humidity:<?=$row["humidity"]?>},<?
}
}
?>
];
<?php
$conn->close();
?>
varchart=c3.generate({
bindto:'#chart',
data:{
x:'ttime',
xFormat:'%Y-%m-%d%H:%M:%S',
keys:{
x:'ttime',
value:['temperature','humidity']
},
json:json,
axes:{
temperature:'y',
humidity:'y2'
}
},
axis:{
x:{
type:'timeseries',
tick:{
format:'%Y-%m-%d%H:%M'
}
},
y:{
label:'temperature'
},
y2:{
show:true,
label:'humidity'
}
}
});
</script>
</body>
</html>
Wewantthispagetobethedefaultstartpagethatwebbrowsersgetwhenevertheyaccess
theserverdirectlywithonlyanIPaddress.Youcanbackuptheolddefaultstartpagefor
Apacheasfollows:
sudomvindex.htmloldindex.html
NavigatingtotheIPaddressofthePifromabrowserwillresultinaviewsimilartothe
followingscreenshotafterafewhoursofsensormeasurements.Here,IcanaccessthePi
usingtheexternalIPaddressoutsidemyhomenetworkasIhaveaddedtheHTTPportof
80totheportforwardingsettingsofmyhomerouter.
Now,wehavearunningFTP,database,andwebservers.Let’sadministertheseusing
ConnectBot.
Simplemanagementofservers
ThefollowingcommandsimplychecksthestatusoftheFTPserver:
servicevsftpdstatus
ThiscommandrestartstheFTPserverifthere’sanyproblemwithit:
sudoservicevstfpdrestart
Theserviceutilitythatwehaveusedletsyourestartthedatabaseandwebserverusing
thesetwocommands:
sudoservicemysqlrestart
sudoserviceapache2restart
UsethefollowingcommandtocheckthestatusoftheMySQLserver:
mysqladmin-uroot-pstatus
Ifyoubelievethatthedatabasehasgrowntoomuchinsize,youcanstarttheMySQL
consoleandrunaSQLquerytoseethedatabasesize:
mysql–uroot–p
mysql>SELECTtable_schema"DB",Round(Sum(data_length+index_length)/
1024/1024,1)"SizeinMB"
FROMinformation_schema.tables
GROUPBYtable_schema;
Youcanevendeleterecordsthatareolderthanthreedaysusingthefollowingquery:
selectmeasurements;
deletefrommeasurementswherettime<NOW()-INTERVAL3DAY;
Or,asanalternative,youcancheckthesizeofthefilesystemusingtheshellcommand:
df-h
Summary
ThischapterintroducedyoutothemanagementofRaspberryPiasaserverandhowto
issuecommandstoitfromAndroid.WeinstalledanFTPserveronthePiandsharedfiles
betweenAndroidclients.Toshowanexampleofdatabaseandwebservers,we
implementedausefulprojectandlearnedtomanagetheseserversremotelyaswell.
ThenextchapterwillintroduceyoutothePicameraandhelpyouimplementa
surveillancesolution.
Chapter3.LiveStreamingofa
SurveillanceCamerafromthePi
Inthischapter,wewillconnectacameratoRaspberryPiandstreamalivevideofromit.
WewillthenbeabletowatchthestreamingofthiscontentfromourAndroiddevice.This
chapterwillmoveusclosertousageandawayfromadministrationofRaspberryPi.
Inthischapter,wewillcoverthefollowingtopics:
Hardwareandsoftwareconfigurations
StreamingvideotoanAndroiddevice
Thesurveillancemode
Hardwareandsoftwareconfigurations
WewilluseastandardcameradevelopedforthePithatcostsabout$30inmanymajor
electronicsstores.
ThePicamera
Pihasacameraportwhereyoucanpluginthecameracable.TheplugonthePicanbe
openedbypullingitupwards.IfyouhaveproblemsconnectingthecameratothePi,you
canfindmanyvideosontheInternetshowinghowtodoit.Youcanwatchonefrom
RaspberryPiFoundationathttps://www.raspberrypi.org/help/camera-module-setup/.
ThenextstepistoconfigurethePiandenablethecamerahardware.Thisisdoneusing
thePiconfigurationprogramaccessedbyissuingthefollowingcommand:
sudoraspi-config
Inthemenuprovided,selectEnableCameraandhitEnter.ThenclickonFinishwhere
you’llbepromptedtoreboot.
StreamingvideotoanAndroiddevice
TheeasiestwaytostreamfromthePitoAndroidisusingtheRaspiCamRemoteappthat
logsintothePiandexecutesthenecessarycommands.Itthenautomaticallygetsthe
streamfromthePi.Downloadandopentheapp,whereyouwillgetaninitialviewto
providelogindetails,suchastheIPaddress,username,andpassword.Notethatby
default,itusesthedefaultloginaccountdetailsandSSHport.YouwillonlyneedtheIP
addressifyouhavethedefaultinstallationinplace.Youcanevenaccessyourcamera
fromtheInternetifyouenableportforwardingforport22,asdescribedinChapter1,
MakeaRemoteDesktopConnectiontoYourPifromAnywhere.Thefollowingscreenshot
displaystheloginsettingsoftheRaspiCamRemoteapp:
InitialviewforRaspiCamRemoteapp
Afterwaitingafewseconds,youshouldseethefirstpicturetakenbytheRaspberryPi
cameraonyourAndroiddevice.Onpressingthecameraicon,thecamerawillstart
streamingasshowninthefollowingscreenshot:
StreamingfromPi
ThenextstepistogetbetterstreamingqualityusingtheH.264setting.Afterconnecting
totheRaspiCamRemoteapp,youshouldopensettingsandchecktheH.264checkbox.
However,beforeconnectingthroughtheappagain,weneedtoinstallaVLCserveronthe
Piusingthefollowingcommand.Youmayexperienceproblemswiththeinstall
commandsfromtimetotime,butrunningitonceagainalmostalwayssolvestheproblem:
sudoapt-getinstallvlc
ThenextstepistoinstallabetterVLCclientontheAndroid.WewillusetheVLCfor
Androidbetaapp.Afterinstallingit,openRaspiCamRemoteappagain,andthenstart
streamingbyclickingonthecameraicon.Atthispoint,Androidwillaskyoutoselectthe
standardvideoplayerorthenewlyinstalledVLCforAndroidbeta.Choosethelatterand
youwillexperienceamuchbetterstreamingquality.Donotforgettoaddport8080tothe
portforwardingsettingsonyourroutertogetaccesstothestreamingvideooverthe
Internet.
ManualVLCconfigurations
TheRaspiCamRemoteappautomaticallyconfiguresVLConthePibeforeitstreams
videocontent.Someofyoumightwanttoconnecttothevideostreamdirectlyfromthe
VLCappandskipRaspiCamonAndroid.Thefollowingcommandisthesameastheone
thatRaspiCamissuesfromtheaccountthatyouprovidebeforeyoustartstreamingusing
RaspiCamonyourAndroiddevice:
/opt/vc/bin/raspivid-o--n-t0-fps25-rot0-w640-h480|
/usr/bin/vlc-Idummystream:///dev/stdin--sout
'#standard{access=http,mux=ts,dst=:8080}':demux=h264&
Ifyouissuetheprecedingcommand,youwillbeabletoviewthestreamingcontentfrom
theVLCapp.Youcaninitiateaconnectionbyclickingontheantenna-likeicononthe
actionbaroftheVLCapp.Itwillpromptforthestreamaddress,whichis
http://PI_IP_ADDRESS:8080.
Thesurveillancemode
Itiscooltoseethestreamingfromyourcamera,butitismuchmoreusefultobeableto
runitinsurveillancemode.Wewantthecameratoreacttomotionandsaveimagesor
videoswhenevermotionisdetected,sothatwecancheckthemlaterinsteadofkeepingan
eyeonthevideo.Forthispurpose,wewillbegininstallingamotionrecognitionsoftware
onourPi,whichiscalledforapparentreasons,motion:
sudoapt-getinstallmotion
Thiswillinstallthemotionsoftwareandthefollowingcommandwilladdthenecessary
packagestothekernel:
sudomodprobebcm2835-v4l2
Itisagoodideatoputthisinthe/etc/rc.localfilesothatitcanberunatstartup.You
shouldputitbeforetheexit0line,though.
Wewillevenmakesomeconfigurationchangestobeabletoaccessthestreamingand
controlfeaturesthatmotionprovides.Edittheconfigurationfileofmotionusingthe
followingcommand:
sudonano/etc/motion/motion.conf
Bydefault,thewebaccesstomotionisrestrictedtothelocalhost,whichmeansthatyou
cannotaccessitfromanothercomputerotherthanthePiitself.Wewillchangethis
behaviorbyfindingthefollowinglinesinthemotion.conffile:
webcam_localhoston
control_localhoston
Notethatthesearenotconsequentlinesinthefile.Also,ifyouusenanoasyoureditor,
youcanpressCtrl+Wtoputitintothesearchmode.
Wewillturnoffthelocalhost-onlyaccessbehaviorbyreplacingtheprecedinglinesof
codewiththefollowingones,respectively:
webcam_localhostoff
control_localhostoff
Inaddition,wewantthemotionservicetoexecuteinthebackgroundmodeaswellbeing
runasdaemon.Forthispurpose,weshouldlocatethefollowinglineofcodeinthesame
file:
daemonon
Weshouldreplaceitwiththisline:
daemonoff
Ifwestartmotionnow,wewillgetthefollowingerror:
Exitmotion,cannotcreateprocessidfile(pidfile)
/var/run/motion/motion.pid:Nosuchfileordirectory
Togetridofthiserror,wecancreatethisfolderthatmotioniscomplainingabout:
sudomkdir/var/run/motion
Notethatthisdirectorymightgetdeletedatstartup,soitisagoodideatoaddthis
commandinthe/etc/rc.localfileaswell.
Now,youcanfinallystartandstopyourPicamerainthesurveillancemode,issuingthe
followingcommands,preferablyusingtheConnectBotapporanyotherSSHclientthat
wediscussedinthepreviouschapter.Thefollowingcommandwillstartmotion:
sudomotion
Tostopmotion,issuethefollowingcommand:
sudopkill-fmotion
Ifyoualwayswanttorunitonstartup,whichIwouldnotrecommendasyoucanrunout
ofstoragespaceonyourPi,youshouldeditthe/etc/default/motionfileusingthe
followingcommand:
sudonano/etc/default/motion
Inthisfile,youwillfindthefollowingline:
start_motion_daemon=no
Youshouldreplaceitwiththisone:
start_motion_daemon=yes
YoumayeitherusethefollowingcommandtostarttheserviceorrebootyourPi,which
willstarttheserviceautomatically:
sudoservicemotionstart
Tocheckthestatusofalltheservicesaswellasthemotionservice,youcanusethe
followingcommand:
sudoservice--status-all
Motionsoftwarecomesintwoparts.Thefirstpartiswhereyoucanwatchstreaming
videos,andthesecondpartiswhereyoucanseeimage/videofileswhenmotionis
detected.Youcanseethestreamfromthemotionsoftwarebyopeningthe
http://IP_ADRESS_OF_THE_PI:8081webpage.Forsomereason,thispartofthemotion
softwareonlyworksinFirefox,butthesurveillancepartdiscussedinthenextsectionwill
workwithotherbrowsers.NotethatyoucannotstartboththemotionserverandVLC
throughtheRaspiCamappatthesametimeastheyusethesameport.Thefollowing
screenshotshowsthestreamingofamotionvideo:
Amotionstreamingvideoonport8081
YoucanlogontoPiusingAndFTPasdiscussedinthepreviouschapterandnavigateto
the/tmp/motionfoldertoseeimagessavedwhenevermotionisdetected.Restartingthe
motionservicewillemptythecontentsofthefolder.
Tip
Addports8080,8081,andFTPport21toyourportforwardingsettingsinsideyourrouter
toaccesstheseservicesfromoutsideyournetwork.
AccessingsurveillanceimagesontheWeb
Inalmostallscenarioswheresurveillanceisinvolved,wewanttoaccesssavedimages
fromwhenmotionwasdetectedthroughtheInternet.Todothis,wewillconnectthe
directorytowhichmotionsavesimagestotheApacheServerwehavealreadyinstalledin
thepreviouschapter.Runningthefollowingcommandwilldothistrick:
sudoln-s/tmp/motion/var/www/motion
Youshouldalsoaddthisdirectorytowhichmotionsavesimagesandvideosintothe
motion.conffileusingthefollowinglineinthefile:
target_dir/tmp/motion
Now,openthehttp://IP_ADRESS_OF_THE_PI/motionlinkinabrowserandyouwillsee
theimagelistingthatmotionhassavedwhenevermotionisdetectedinfrontofthe
camera.
Notethatyoumaygetanaccessforbiddenfaultfromthewebbrowserifmotionhasnot
yetdetectedanymotionandcreatedthe/tmp/motion/directory.Thefollowingscreenshot
illustratestheimagelistingthatmotionhassaved:
ImageandvideofileswhenmotiondetectedaccessedthroughtheWeb
Summary
WehavemovedawayfromadministrationofPitomorereal-lifeprojectsandinstalleda
cameraonthePi;thereby,viewingstreamsfromthePionbothanAndroiddeviceandthe
Web.WehaveevenlearnedhowtousethePiasasurveillancecameraandseemotion
detectedbyit.
WewillcontinueusingthePiinanevenmoreinterestingscenariointhenextchapterand
turnitintoamediacenter.
Chapter4.TurnYourPiintoaMedia
Center
WehavebeenadministeringourPiandimplementingusefulprojectsintheprevious
chapters.Inthischapter,wewilluseourPimoreasasourceofentertainmentandturnit
intoamediacenter.Thetopicscoveredareasfollows:
InstallingandsettingupamediacenteronthePi
ConnectingtoamediacenterviaremotecontrolfromAndroid
Gettingmorefromyourmediacenter
InstallingamediacenterusingNOOBS
Installingandsettingupamediacenteron
Pi
Themediacentersoftwarewe’vechosenforthepurposeofthisprojectisKodi,formerly
knownasXBMC.Itisopensourceandwidelyusedwithlotsofadd-ons.
Asusual,wewillstartbyinstallingthenecessarysoftwareonourPiusingtheapt-get
command:
sudoapt-getinstallkodi
Then,we’llrunthekodi-standaloneexecutable,whichwillstartKodiandshowitsuser
interfaceontheHDMIportofthePi.Itis,therefore,importantthatyouconnectthePitoa
screenusingtheHDMIportinsteadofaremotedesktoptoseeKodi’suserinterface.Now,
youcanconnectaUSBkeyboardormousetonavigateinsideKodi.
StartingKodionboot
Wedefinitelydonotwanttorunacommandtostartthemediacenter,nomatterhoweasy
itistoruncommandsfromAndroid,asdiscussedinpreviouschapters.Forthisreason,we
needtostartthecommandonstartupusingthecrontab-ecommand.Addthefollowing
lineattheendofthefilethecrontabcommandcommandopens:
@reboot/usr/bin/kodi-standalone&
Now,wheneveryourestartthePi,Kodiwillberestartedautomatically.Notethat,here,
youaccessthemediacenterthroughtheHDMIportofthePi,butyouwillalsobeableto
accessviaremotedesktopusingthetoolsdiscussedinChapter1,MakeaRemoteDesktop
ConnectiontoYourPifromAnywhere.
Connectingtothemediacenterviaremote
controlfromAndroid
Themainproblemwiththecurrentsetupisthatyoucanonlycontrolthemediacenter
usingaconnectedkeyboardormouse,makingitnotascomfortabletouseasamedia
centershouldbe.However,thereisaremotecontrolforKodionAndroid,calledKore,
thatmakesitreallyeasytoremotelycontrolthemediacenter.Youcandownloaditfrom
GooglePlay.ItsofficialnameisKore,OfficialRemoteforKodianditispublishedby
theXBMCFoundation,whichisanonprofitorganizationthatoperatestheKodiMedia
Centerproject.
BeforeyoucanconnecttheremotecontrolapplicationonAndroidtotheKodiinstallation
onthePi,youneedtomakesomesetupchangesonKodi.GototheSYSTEMmenuin
Kodi,andthenSettings,Services,andWebserver.Here,youshouldselectAllowcontrol
ofKodiviaHTTP.ThengototheRemotecontrolsettingsinsamemenuandenablethe
AllowprogramsonthissystemtocontrolXBMCandAllowprogramsonother
systemstocontrolXBMCsettings.NowopenKoreonAndroidandletitsearchforthe
mediacenter.Ifboththephoneandmediacenterareonthesamenetwork,Koreshouldbe
abletofindit.Whensucceededwiththesearch,youwillseeaviewsimilartothe
followingscreenshot:
Tip
NotethatthedefaultHTTPportforKodicollideswiththemotionserver’sdefaultHTTP
port,whichwesawinthepreviouschapter.Youshouldeitherchangetheportsettingin
KodiorstopthemotionserverbeforemakingthesechangesinKodi’ssettings.
Korehasfoundthemediacenter
Now,clickonthenewlyfoundmediacentertoconnectandstartcontrollingitremotely.If
itdoesnotidentifythemediacenterautomatically,youcanpresstheNextbuttonand
entertheparametersmanually.Port8080isthedefaultportandkodiisthedefault
usernameyoushoulduseifyouhaven’tchangedtheseparametersinsideKodi.
ManualsettingsinKore
Gettingmorefromyourmediacenter
Therearemanythingsamediacentercanbeusedfor.Youcan,forexample,download
add-onsthatgiveyouaccesstolotsofonlinecontent,suchasYouTube,KhanAcademy,
andTEDTalks.
WatchingvideosusingKodionanAndroiddevice
AnotherinterestingthingyoucandoistouploadvideofromyourphonetothePiusing
thepreviouslydiscussedAndFTPappfromChapter2,ServerManagementwithPi,and
thenwatchmoviesusingthemediacenter.YouneedtoaddadirectoryontothePiwhere
youwilluploadthesefilesasamedialocationinKodi.GotoVideos|Files|Files,and
thennavigatetoAddVideos….Here,youshouldfirstselectBrowse,andthenRoot
filesystem.Notethatwewereusing/home/piasthetargetforuploadsinChapter2,
ServerManagementwithPi.Itshouldworkeveninthiscase.Browsedowntothis
locationandclickonOKonallthreepopups.YoushouldnowseethePiinthelistof
VideosonKodi.Youcanevenaddthisfoldertofavoritesforeasyaccess.OpentheKore
remotecontrolappandbrowsetothepifolderonceagainunderVideos.Whenthepi
folderishighlightedinKodi,pressthepropertiesbuttonintheKoreremotecontrolapp.
ThenselectAddtofavoritesbyscrollingdownusingthearrowsonKore.
ThebuttonthatliststhechoicesinKore,thatis,thepropertiesbutton
NextopenAndFTPfromChapter2,ServerManagementwithPi,andconnecttothePior
selecttheconnectionthatisalreadysavedfromprevioussessions.Youshouldnowseethe
contentsofthe/home/pidirectory,whichisthedefaultlocationfortheuserpiwehave
used.Thisisthetargetlocation.Then,selectthemobilephoneimageontheactionbarin
AndFTPtoselectavideolocatedonyourmobilephoneanduploadittoKodi.
TheAndFTPinterfacetoselecttheuploadlocationfromthephonetothePi
RecordedvideosaregenerallylocatedunderDCIM/Camera.Selectthevideosyouwantto
upload.Then,clickontheuploadiconintheactionbar:
TheAndFTPinterfacetobeginuploadfromthephonetothePi
Next,youcanbrowsedowntothepidirectoryinKodithatwehaveaddedtotheVideos
sectionandseethevideosyouhavejustuploadedonyourmediacenter.
StreamingtheAndroiddisplaytoKodi
AnotherveryinterestingthingyoucandoistostreamyourAndroidscreenandmake
Kodishowthisstream.Forthispurpose,wewillfirstdownloadanappfromGooglePlay
thatwillstreamanAndroiddisplayandpublishitusingaURLonyourinternalnetwork.
TheappwewilluseforthispurposeiscalledScreenStreamMirroringandcomesboth
asafreeandapaidversion.Forthesakeofthisproject,itisenoughtodownloadthefree
version.Afterstartingtheapp,youwillneedtocloseafewadvertisementsandpressthe
StartNowbuttononthepop-up.
ScreenStreamMirroring
Here,youwillseetheaddressthatthestreamingispublishedto.Wewillnowsavethis
rtsp://YOUR_ANDROID_IP_ADRESS:5000/screenlinkinafilewewillcallstream.strm
onthePiunderthehomedirectoryoftheuserpi,whichis/home/pi.Then,browsetothe
pidirectoryinKodi,findthisfile,andopenit.Rememberthatwehavesavedthis
directoryundertheVideossectioninKodiandasafavoriteaswell.Now,youshouldbe
abletoseewhateveryoudoontheAndroiddevice’sscreenattachedtothePi’sHDMI
portusedbyKodi.AnotheroptionhereistoshowtheAndroidcameracapturethrough
thischannel.TheScreenStreamMirroringappweusehasanotificationintheAndroid
notificationarea.Ifyouexpandit,youwillseeanoptionnamedCAMERA.Bypressing
thisbutton,youwillbeabletostartthecameraandseethecameracaptureaswell.
TheScreenStreamMirroringnotificationwiththecameraoption
InstallingthemediacenterusingNOOBS
AnotheroptionforinstallingthemediacenterontothePiisusingNOOBS.Thisway,
userscanveryeasilyinstallthemediacenterwithoutworryingaboutdetailsrelatedto
RaspbianOS,aswedidinthischapter.WehavealreadycoveredtheNOOBSinstallation
inChapter1,MakeaRemoteDesktopConnectiontoYourPifromAnywhere.However,in
Chapter1,MakeaRemoteDesktopConnectiontoYourPifromAnywhere,weusedthe
offlineinstallationoption.Wecanusetheonlineinstallationoptioninstead.Youshould
downloadtheonlineNOOBSinstallerfrom
http://downloads.raspberrypi.org/NOOBS_lite_latest.ThisZIPfileismuchsmallerbut
youneedtoconnectthePitoanEthernetnetworkbeforeyoubegininstallation.Extract
thecontentsofthefiletoanSDcardandrestartyourPiwiththisSDcardinserted.Now,
youwillseealistofoperatingsystemstoinstall.Thelistcontainstwomediacentersas
well.TheseareOpenELECandOSMC.BotharebasedonKodi,whichwe’vealready
coveredinthischapter.
Summary
Thischapterwasshort,butfun.WehavelearnedtoinstallonourPiandsetuponeofthe
mostwidelyusedmediacentersandcontrolitremotelyfromourAndroiddevice.
Inthenextchapter,wewillgetourhandsdirtyandbeginsomePythonandAndroid
programming,andmakeuseofevenmoreconnectionpossibilitiesbetweenthePiand
Android.
Chapter5.MissedCallswithPi
Inthischapter,wewillimplementamuchmoreprogramming-orientedprojectanddive
intoBluetoothSmartorBluetoothLowEnergy(BLE)programming.Wewillmakethe
PiandAndroidphonescommunicatethroughBluetooth,andcontrolthePiusingthis
channel.Wewillcoverthefollowingtopicsinthischapter:
Installingthenecessarycomponents
AddingasensorservicetoBluetoothLowEnergy
ConnectingfromanAndroidapp
SendingtherebootcommandfromyourAndroidphonetothePi
SendingmorecommandsfromyourAndroidphonetothePi
Installingthenecessarycomponents
ThehardwarecomponentneededforthisprojectisaBLE-enabledBluetoothUSBdongle.
ItisimportantthatthishardwaresupportsBLEaswewillspecificallymakeuseofthis
partoftheBluetoothstack.WewilluseonebyPlugable,whichisavailableonAmazon.
TheBluetoothdonglebyPlugable
TheRaspbiandistributionthatwehavedownloadedalreadycontainssupportfor
Bluetooth,butweneedtoupdateBluetoothpackagesforbetterLEsupport.Youcanbuild
andinstallamoremodernoftheBluetoothpackageversionusingthefollowing
commands:
sudoapt-getinstalllibdbus-1-devlibdbus-glib-1-devlibglib2.0-dev
libical-devlibreadline-devlibudev-devlibusb-devmake
mkdir-pwork/bluepy
cdwork/bluepy
wgethttps://www.kernel.org/pub/linux/bluetooth/bluez-5.33.tar.xz
tarxvfbluez-5.33.tar.xz
cdbluez-5.33
./configure--disable-systemd
make
sudomakeinstall
ThemakestepwillcompilethenecessarypackagesneededforthePiandwilltakeabout
15minutestocomplete.However,you’llneedtobepatientasitwillleadtosomething
coolandusefulattheend.NotethatthelatestversionofBlueZis5.33atthetimeof
writingthisbook,andyoucaninsteadreplaceitwiththelatestversionbycheckingthelist
ofallavailableversionsathttps://www.kernel.org/pub/linux/bluetooth/.Noteherethatwe
havedisabledthesystemdsupportusingthe--disable-systemdoption,whichcauses
builderrors,otherwise.
Theprecedingcommandshavealsoinstalledsomecommand-linetoolstoletusconfigure
andscanforBluetoothdevices.Thefollowingcommandlistsalltheattachedcomponents
ontheUSBportsofthePi:
lsusb
Theoutputoftheprecedingcommandisasfollows:
Bus001Device002:ID0424:9514StandardMicrosystemsCorp.
Bus001Device001:ID1d6b:0002LinuxFoundation2.0roothub
Bus001Device003:ID0424:ec00StandardMicrosystemsCorp.
Bus001Device004:ID0a5c:21e8BroadcomCorp.
Bus001Device005:ID148f:5370RalinkTechnology,Corp.RT5370Wireless
Adapter
TheBluetoothadapterisnamedBroadcominmycase.Togetmoredetailsonaspecific
device,usethefollowingcommand:
sudolsusb-v-d0a5c:
Here,notethat0a5cisthefirstpartoftheaddressoftheBluetoothdonglethatIam
reusingtogetmoreinformationononlythisdevice.
ThehciconfigtoolwillshowyouwhichdevicessupportBluetooth.Thiscommand
outputsthefollowinginformationonmysystem:
hci0:Type:BR/EDRBus:USB
BDAddress:5C:F3:70:68:BE:42ACLMTU:1021:8SCOMTU:64:1
DOWN
RXbytes:564acl:0sco:0events:29errors:0
TXbytes:358acl:0sco:0commands:29errors:0
Asseenhere,thedeviceismarkedasDOWN.Wewillkeepitthiswayasthenexttoolwe
installrequiresittobedowninitially.
Note
ThereareusefulBluetoothLEcommandsthatyoucanusetocheckforotherBLE
devices.Wewillnotusethesecommandsyet,butitisagoodpracticetoplaywiththemto
checkifyourBLEdevicesareworkingoraccessible.
Thesamehciconfigtoolthatwe’veusedpreviouslyhelpsusbringtheBluetoothdevice
up.However,donotdothisifyouwanttoproceedwiththerestofthechapterasthenext
toolrequiresittobedown:
sudohciconfighci0up
Itisagoodideatoputthiscommandincrontab,asdiscussedpreviously,usingcrontab
withthe–eoptioninordertoletyouusenanoastheeditorandinstallnewcrontab
automatically.Add@rebootsudohciconfighci0upinsidethefileattheend,andsave
andexit.
Therearetwoothercommandswecanuse:
sudohcitoollescan
ThiscommandliststheBLEdevices.Nowlet’stakealookatthefollowingcommand:
sudohcitoollecc68:64:4B:0B:24:A7
AndthiscommandteststheBluetoothconnectiontothedevice.Notethattheaddress
providedtothelattercommandwasreturnedbytheformer.
WewillevenneedaprogrammingsupportforBluetooth.WewilluseGoasthelanguage
andtheGattpackageforGothatgivessupportforBluetoothLEintheGolanguage.The
GenericAttributeProfile(Gatt)isageneralspecificationtosendandreceivesmall
amountsofdata,knownasattributes,overaBLElink.Let’srunthefollowingcommands
toinstallthegolanguage:
cd
gitclonehttps://go.googlesource.com/go
cdgo
gitcheckoutgo1.4.1
cdsrc
./all.bash
Youmightwanttogoandgrabacupofcoffeehere,asthelastcommandwilltakeabout
40minutestocomplete.Attheendoftheoutput,youwillseethatthegoinstallerasksyou
toaddabinarydirectorytoyourpathforeasyaccess.Thefollowingcommandscan
accomplishthis:
PATH=$PATH:/home/pi/go/bin
exportPATH
exportGOROOT=/home/pi/go
exportGOPATH=/home/pi/gopath
Tip
Itisagoodideatoputthesecommandsinthe/etc/profilefileinordertoexecutethem
foreachsessionthatyoustartinthefuture.Besuretoaddthemattheendofthefile,
though.Also,donotforgettoactuallyexecutethemeventhoughyouhaveputtheminthe
profilefileifyouwanttocontinuewithoutrebooting.
Then,usethefollowingcommandtodownloadtheGattpackagesourcefiles:
gogetgithub.com/paypal/gatt
NowwewillstartasimpleBLEserverusingthefollowingcommand:
cd/home/pi/gopath/src/github.com/paypal/gatt
gobuildexamples/server.go
sudo./server
Tip
Aftercompletingthischapter,youmightwanttoputtheserverstartupcommandinside
crontabusingthefollowingcommand:
crontab-e
ThiswaytheBLEserverwillstarteachtimeyourebootthePi.Addthefollowinglineat
theend:
@rebootsudo/home/pi/gopath/src/github.com/paypal/gatt/server
ItisnowtimetofindourRaspberryPi,whichbehaveslikeaBLEdevicefromAndroid.
WewillusetheBLEScannerappbyBluePixelTechnologiesandisavailableonthePlay
Store.Whenyoustartit,youwillseealistofBLEdevicesavailablearoundyoualong
withtheiraddresses.TheaddressoftheBluetoothadapteronthePicanbeseenusingthe
hciconfigcommand.ThedefaultimplementationoftheGattservernamesthedeviceas
Gopher.ThefollowingscreenshotillustratestheBLEScannerapp,showingthePiasa
BLEdevice:
TheBLEScannerappshowingthePiasaBLEdevice
TheBLEstackisdesignedinawaythatadevicesupportssomenumberofservicesthat
userscanconnectto,andeachservicecanprovideread/writeornotification
characteristics,whichismainlydatathatyoucanwriteto,read,orgetnotificationsfrom.
ClickonthedeviceintheappandyouwillconnecttothePi’snewlystartedBLEserver.
Youwillbepresentedwithfourservices.Theoneweareinterestediniscalled
UNKNOWNSERVICE,whichisunnamedbecauseitisnotastandardserviceanditis
implementedtoonlydemonstratetheGattexampleserver.Clickonthisserviceandyou
willseethreecharacteristicsprovidedbythisservice:READ,WRITE,andNotification.
Youcanrecognizethetypeofcharacteristicbylookingatwhichoneofthethreebuttons
onBLEScannerappisenabled.ThefollowingscreenshotillustratestheREAD
characteristics:
TheREADcharacteristic
AddingasensorservicetoBluetoothLow
Energy
WewilladdanewservicetothealreadyexistingexamplefromGatt.Thisnewservice
willpublishtwonewcharacteristicstobeginwith:oneforhumidityandtheotherfor
temperaturemeasurements.Wewillreadthemeasurementsthesamewayusingthe
techniqueswe’vediscussedinChapter2,ServerManagementwithPi.Toreadthese
measurements,wewillcreatetwonewfileswithcontentsimilartothesense.pyfilethat
wediscussedChapter2,ServerManagementwithPi.Let’screatetwofilesunderthehome
directory,andnamethemhumidity.pyandtemperature.py.Thetemperature.pyfile
hasthefollowingcontent:
#!/usr/bin/python
importsys
importAdafruit_DHT
humidity,temperature=Adafruit_DHT.read_retry(Adafruit_DHT.DHT11,4)
printstr(temperature)
Thehumidity.pyfilehassimilarcontent.Theonlydifferenceisthatitprintsoutthe
humiditypartofthemeasurementinsteadofthetemperature:
#!/usr/bin/python
importsys
importAdafruit_DHT
humidity,temperature=Adafruit_DHT.read_retry(Adafruit_DHT.DHT11,4)
printstr(humidity)
Weneedtochangethefileaccessmodetoexecutableaswellusingthefollowing
command:
chmod+xtemperature.pyhumidity.py
Now,youcantestsensormeasurementsusingthefollowingcommands:
sudo./temperature.py
sudo./humidity.py
ThenextstepistopublishthesereadingsviatheBluetoothchannel.Wewillcreateanew
serviceinsidetheexistingGattserverexample.Forthispurpose,youcanstarteditingthe
server.gosourcefilefortheserverexampleinthe
/home/pi/gopath/src/github.com/paypal/gatt/examplespath.Youonlyneedtoadd
threelinesofcodeinthefunctiondefinitionforonStateChangedinbetweenotherservice
definitions.Inthefollowingcontent,notethatthecountserviceandbatteryservice
alreadyexist.Weonlyneedtoaddthesensorservice:
//Asimplecountservicefordemo.
s1:=service.NewCountService()
d.AddService(s1)
//Asensorservicefordemo.
sSensor:=service.NewSensorService()
d.AddService(sSensor)
//Afakebatteryservicefordemo.
s2:=service.NewBatteryService()
d.AddService(s2)
Additionally,inthesamefile,changethelinewherenewservicesareadvertisedtothe
followingcodeinordertoadvertisethenewserviceaswell:
//Advertisedevicenameandservice'sUUIDs.
d.AdvertiseNameAndServices("Gopher",[]gatt.UUID{s1.UUID(),sSensor.UUID(),
s2.UUID()})
Weneedtoaddthedefinitionforthenewservicealso.Thefollowingcodeshouldbe
placedinafile,namedsensor.go,undertheservicedirectoryoftheGattexamplesatthe
samelevelasotherservicedefinitionfiles,suchascount.goandbattery.go:
packageservice
import(
"fmt"
"log"
"os/exec"
"strings"
"github.com/paypal/gatt"
)
funcNewSensorService()*gatt.Service{
s:=gatt.NewService(gatt.MustParseUUID("19fc95c0-c111-11e3-9904-
0002a5d5c51b"))
s.AddCharacteristic(gatt.MustParseUUID("21fac9e0-c111-11e3-9246-
0002a5d5c51b")).HandleReadFunc(
func(rspgatt.ResponseWriter,req*gatt.ReadRequest){
out,err:=exec.Command("sh","-c","sudo
/home/pi/temperature.py").Output()
iferr!=nil{
fmt.Fprintf(rsp,"erroroccured%s",err)
log.Println("Wrote:error%s",err)
}else{
stringout:=string(out)
stringout=strings.TrimSpace(stringout)
fmt.Fprintf(rsp,stringout)
log.Println("Wrote:",stringout)
}
})
s.AddCharacteristic(gatt.MustParseUUID("31fac9e0-c111-11e3-9246-
0002a5d5c51b")).HandleReadFunc(
func(rspgatt.ResponseWriter,req*gatt.ReadRequest){
out,err:=exec.Command("sh","-c","sudo
/home/pi/humidity.py").Output()
iferr!=nil{
fmt.Fprintf(rsp,"erroroccured%s",err)
log.Println("Wrote:error%s",err)
}else{
stringout:=string(out)
stringout=strings.TrimSpace(stringout)
fmt.Fprintf(rsp,stringout)
log.Println("Wrote:",stringout)
}
})
returns
}
Weneedtobuildandrerunourservercodeusinggo.Thefollowingcommandsthatwe
usedearlierwillhelpusdothis.Notethatyoushouldbeinthe
/home/pi/gopath/src/github.com/paypal/gattdirectory:
gobuildexamples/server.go
sudo./server
WecanusetheBLEScannerapponAndroidagaintoconnecttothisnewserviceandread
thetemperatureandhumiditysensorvalues.Thefollowingscreenshotillustratesthe
Gopherservices:
AfterconnectingtotheGopherdevice,youshouldseethenewlyaddedservicewiththe
19fc95c0-c111-11e3-9904-0002a5d5c51bID,andnewcharacteristicsforthatserviceas
showninthefollowingscreenshot:
Newlyaddedcharacteristics:onefortemperatureandtheotherforhumidity
measurements
Thefollowingscreenshotillustratesthecharacteristicdetailsfortemperaturemeasurement
afterpressingthetheReadbutton:
Characteristicsfortemperaturemeasurementshowingacurrentvalueof27degrees
ConnectingfromanAndroidapp
WehaveusedanexistingapptoconnecttotheBLEservicethatweimplementedon
RaspberryPi.Thisapp,calledBLEScanner,isverygeneralpurposeandwouldworkfor
anykindofBLEdevice.However,weneedamorespecializedappthatonlyreads
measurementsandabstractsawaydetailsoftheBLEprotocol,suchasdevicescan,
services,andservicecharacteristics.Inthissection,wewillimplementanAndroidappto
connecttotheRaspberryPiBLE.WeneedtoinstalltheAndroidStudioforthispurpose.
AndroidstudioisspecificallydesignedforAndroidappdevelopmentbyGoogle.Youcan
readmoreaboutitbyvisitinghttp://developer.android.com/tools/studio/.Youcanfind
instructionsforinstallationathttp://developer.android.com/sdk/.Wewillusearealdevice
totestourappandnotthebuilt-inemulator.Forthispurpose,youmayneedtoinstall
devicedriversspecifictoyourAndroidphoneandmakeconfigurationchangestothe
AndroidStudioinstallation.Thehttp://developer.android.com/tools/device.htmllinkwill
helpyoucarryouttheseactions.
Now,starttheAndroidStudioandchooseanewprojecttocreate.Iwillnamethe
applicationBLEPiandthedomainexample.com.YoushouldchoosePhoneandTabletas
theformfactor,andatleastAndroid5.0astheminimumSDKasbetterBLEsupportis
introducedwiththisSDKtotheAndroidsystem.ThecoreBLEsupportisactuallyadded
toAndroid4.3,andthecodefilesdistributedonthebook’swebsiteaswellastheGitHub
repositoryofthebookwillworkforAndroid4.3aswellasAndroid5.0.However,forthe
sakeofsimplicityandease,theupcomingcodeisforAndroid5.0only.Notethatyou
shouldhavedownloadedAndroid5.0SDKduringtheAndroidStudioinstallationinorder
tobeabletochooseitinthecreateprojectwizard.Takealookatthelinkswe’vejust
mentionedinthissectionforfurtherdetailsonthis.Then,choosetoaddablankactivityto
theappanddonotchangethenameoftheactivityinthenextstep;wewillkeepitas
MainActivity.
WewillbeginourimplementationbyaddingBluetoothpermissionstothe
AndroidManifest.xmlfileinsidethemanifestandbeforetheapplicationtag:
<uses-permission
android:name="android.permission.BLUETOOTH"/>
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"/>
Then,we’llbeginmakingchangestotheMainActivity.javafile.Startbymakingthe
followingclassvariabledefinitions:
privateBluetoothAdapterbluetoothAdapter;
privateBluetoothLeScannerbleScanner;
privateBluetoothGattbleGatt;
privatestaticfinalintREQUEST_ENABLE_BT=1;
privatestaticfinalUUIDUUID_Service=
UUID.fromString("19fc95c0-c111-11e3-9904-0002a5d5c51b");
privatestaticfinalUUIDUUID_TEMPERATURE=
UUID.fromString("21fac9e0-c111-11e3-9246-0002a5d5c51b");
privatestaticfinalUUIDUUID_HUMIDITY=
UUID.fromString("31fac9e0-c111-11e3-9246-0002a5d5c51b");
ThebluetoothAdapterdefinitionrepresentsthelocaldevice’sBluetoothadapterandlets
youperformfundamentalBluetoothtasks,suchasdiscoveringotherdevicesandgetting
thepropertiesofthediscovereddevices.bleScannerprovidesmethodstoperformscanrelatedoperationsspecifictoBluetoothLEdevicesandbleGattprovidestheBluetooth
GATTfunctionalitytoenablecommunicationwithBluetoothSmartdevices.TheUUIDs
wehavedefinedherearethesameastheoneswehaveusedinthesensor.gofilethatwe
savedonthePipreviouslyfortheidentificationofthenewserviceanditstwonew
characteristics.
Tip
IntheAndroidStudio,youcanusetheAlt+Entershortcutkeytoautomaticallyimport
missingpackages.Thecursorshouldbelocatedontheclassforwhichtheimportis
missinginthejavafile.Or,alternatively,placethecursorontheclass,keepthemouse
pointeronit,andyouwillseealightbulbmenu.Inthismenu,youcanselecttheimport
classoption.
InsidetheonCreatemethod,whichiscalledbytheAndroidsystemwhentheappstarts
forthefirsttime,wecaninitializebluetoothAdapter:
BluetoothManagerbluetoothManager=
(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter=bluetoothManager.getAdapter();
WeneedtodefinethestartScanmethodthatwillbecalledwheneverwewanttoinitiate
ascanofBLEdevices.
privatevoidstartScan(){
if(bluetoothAdapter==null||!bluetoothAdapter.isEnabled())
{
IntentenableBtIntent=
newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,REQUEST_ENABLE_BT);
}else{
bleScanner=bluetoothAdapter.getBluetoothLeScanner();
if(bleScanner!=null){
finalScanFilterscanFilter=
newScanFilter.Builder().build();
ScanSettingssettings=
newScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
bleScanner.startScan(
Arrays.asList(scanFilter),settings,scanCallback);
}
}
}
Here,wecheckifBluetoothisenabledonthedevicefirst.Ifnot,we’llpresentamessage
boxtolettheuserenableBluetooth.Ifitisenabled,we’llgetaninstanceofbleScanner,
whichisusedtostartascanusingthestartScanmethod.Wecangiveacallback
implementationname,suchasscanCallback,whichwillbecalledwheneverascan
returnssomeresults.Now,weneedtodefinethiscallbackvariable,asshowninthe
followingcode:
privateScanCallbackscanCallback=newScanCallback(){
@Override
publicvoidonScanResult(intcallbackType,ScanResultresult){
if("Gopher".equals(result.getDevice().getName())){
Toast.makeText(MainActivity.this,"Gopherfound",
Toast.LENGTH_SHORT).show();
if(bleScanner!=null){
bleScanner.stopScan(scanCallback);
}
bleGatt=
result.getDevice().connectGatt(
getApplicationContext(),false,bleGattCallback);
}
super.onScanResult(callbackType,result);
}
};
TheScanCallbackimplementationoverridesoneimportantmethod,onScanResult,which
iscalledwheneverthereisanynewdevicetoreport.Wethencheckifthedevicenameis
thesameastheonethatwasdefinedintheserver.gofileonthePi.Ifso,wecansavethe
devicepropertiesandconnectioninformationtothebleGattvariable.Wecaneven
connecttothedeviceusingtheconnectGattmethod,andprovideanothercallback
implementation,bleGattCallback,whichwillbecalledwheneveranAndroidsystem
establishesaconnectiontothedevice.Westopthescanifwehavefoundthedevicewe
arelookingfor.Hereisthedefinitionforthiscallback:
privateBluetoothGattCallbackbleGattCallback=newBluetoothGattCallback()
{
@Override
publicvoidonConnectionStateChange(BluetoothGattgatt,intstatus,int
newState){
gatt.discoverServices();
super.onConnectionStateChange(gatt,status,newState);
}
@Override
publicvoidonServicesDiscovered(BluetoothGattgatt,intstatus){
BluetoothGattServiceservice=
gatt.getService(UUID_Service);
BluetoothGattCharacteristictemperatureCharacteristic=
service.getCharacteristic(UUID_TEMPERATURE);
gatt.readCharacteristic(temperatureCharacteristic);
super.onServicesDiscovered(gatt,status);
}
@Override
publicvoidonCharacteristicRead(BluetoothGattgatt,final
BluetoothGattCharacteristiccharacteristic,intstatus){
finalStringvalue=characteristic.getStringValue(0);
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
TextViewtv;
if(UUID_HUMIDITY.equals(characteristic.getUuid())){
tv=(TextView)MainActivity.this.findViewById(
R.id.humidity_textview);
}else{
tv=(TextView)MainActivity.this.findViewById(
R.id.temperature_textview);
}
tv.setText(value);
}
});
BluetoothGattServiceservice=
gatt.getService(UUID_Service);
readNextCharacteristic(gatt,characteristic);
super.onCharacteristicRead(gatt,characteristic,status);
}
};
Inthiscallbackimplementation,weoverridethreeimportantmethodscalledfromthe
Androidsystemondifferenttimes.TheonConnectionStateChangemethodiscalled
wheneveraconnectionisestablishedtotheremotedevicethroughBluetooth.Inthiscase,
wecaninitiatetheservicediscoveryofthedeviceusingthediscoverServicesmethod.
TheonServicesDiscoveredmethodisthencalledwhenservicesarediscoveredonthe
device.Insuchacase,we’llread,tobeginwith,thetemperaturecharacteristicsforthe
sensorservicethatwe’vedefinedonthePiusingthereadCharacteristicmethod.
Wheneverthevalueofthecharacteristicreadingoperationhassucceededthethird
overriddenmethod,onCharacteristicReadiscalledwherewereadthenextcharacteristic
whichishumidity,andthenwaitforthisoperationtosucceedinthesamemethod.Then,
wetaketurnstoreadthehumidityandtemperaturevaluesusingthe
readNextCharacteristicmethodthatwe’lldefineinthesamecallbackimplementation.
ThisisbecausetheBLEprotocoldoesnotletusreadbothcharacteristicsatthesametime.
Let’stakealookatthefollowingcode:
privatevoidreadNextCharacteristic(BluetoothGatt
gatt,BluetoothGattCharacteristiccharacteristic){
BluetoothGattServiceservice=gatt.getService(UUID_Service);
if(UUID_HUMIDITY.equals(characteristic.getUuid())){
BluetoothGattCharacteristictemperatureCharacteristic=
service.getCharacteristic(UUID_TEMPERATURE);
gatt.readCharacteristic(temperatureCharacteristic);
}else{
BluetoothGattCharacteristichumidityCharacteristic=
service.getCharacteristic(UUID_HUMIDITY);
gatt.readCharacteristic(humidityCharacteristic);
}
}
Whenevertherespectivereadoperationsucceeds,wegetthevalueofthemeasurement
usingthegetStringValuemethodofthereturnedcharacteristicobject,andthenshow
itintheUIelementsthatwewilldefineintheactivity_main.xmlfileasfollows:
<TextView
android:id="@+id/temperature_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"/>
<TextView
android:id="@+id/humidity_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Forthecodetobecomplete,weneedtodefinethefollowingmethodsaswellinthe
MainActivity.javafile:
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intent
data){
if(requestCode==REQUEST_ENABLE_BT){
startScan();
}
super.onActivityResult(requestCode,resultCode,data);
}
@Override
protectedvoidonResume(){
startScan();
super.onResume();
}
@Override
protectedvoidonPause(){
if(bleScanner!=null){
bleScanner.stopScan(scanCallback);
}
if(bleGatt!=null){
bleGatt.close();
bleGatt.disconnect();
bleGatt=null;
}
super.onPause();
}
TheonActivityResultmethodiscalledwheneverauserenablesBluetooth,andweneed
tostartscanninginthiscaseaswellaseverytimetheuserstartsanappwhereonResumeis
called.Iftheuserclosestheapp,theBluetoothconnectioncanbestoppedthroughthe
onPausemethod.
Thisisagreatopportunitytotestourthefirstversionofourappthatwehave
implementedsofarandverifythatitworks.SelectRunappintheRunmenuinthe
AndroidStudio,andyouwillbegivenanoptiontoselectthelocationtoinstalltheapp.
YouwillthenseetheAndroiddevicethatyouhaveattachedtoyourcomputerinthelist.
Sendingtherebootcommandfromyour
AndroidphonetothePi
Untilnow,wehavebeenreceivingdatafromthePithroughBLE.Now,wewillsend
commandstoitusingthesamechannel.Wewillimplementanewwritecharacteristicin
thesameserviceasourtemperatureandhumidityreadcharacteristicsare,whichwere
definedonthePi.Usingthesenewcharacteristics,wewillsendtherebootcommandto
thePi.Let’sbeginbyeditingthesensor.gofileagainandputthefollowingcodeattheend
ofit:
s.AddCharacteristic(gatt.MustParseUUID("41fac9e0-c111-11e3-9246-
0002a5d5c51b")).HandleWriteFunc(
func(rgatt.Request,data[]byte)(statusbyte){
log.Println("Commandreceived")
exec.Command("sh","-c","sudoreboot").Output()
returngatt.StatusSuccess
})
BuildandrestarttheBLEserverusingthefollowingcommands:
cd/home/pi/gopath/src/github.com/paypal/gatt
gobuildexamples/server.go
sudo./server
Now,testthecharacteristicsmentionedpreviouslyusingtheBLEScannerapp.Whenever
youwritesomethingtothesecharacteristics,thePiwillreboot.
ThenextstepistoimplementthisnewrebootfunctionintheAndroidappthatwehave
beenbuilding.
First,addtheUUIDofthethisnewwritecharacteristicswehavejustdefinedanda
variabletocontroltheoperationsequences,asshowninthefollowingcode:
privatestaticfinalUUIDUUID_REBOOT=
UUID.fromString("41fac9e0-c111-11e3-9246-0002a5d5c51b");
privatevolatilebooleanisSendReboot=false;
Thebooleanvariable,isSendReboot,willbeusedtoinitiatethewritecharacteristic
operationandorchestrateittogetherwiththereadoperationspreviouslydefined.TheBLE
stackcannothandleread/writeoperationsthataretooclosetoeachother,andwewantto
avoidperformingoneoperationbeforethepreviousoneiscompleted.Then,inthe
onCharacteristicReadfunctionofbleGattCallback,changethelinewherewecall
readNextCharacteristicwiththefollowingpieceofcode:
if(isSendReboot){
BluetoothGattCharacteristicrebootCharacteristic=
service.getCharacteristic(UUID_REBOOT);
rebootCharacteristic.setValue("reboot");
gatt.writeCharacteristic(rebootCharacteristic);
}else{
readNextCharacteristic(gatt,characteristic);
}
Here,wewillwriteavalue,reboot,totherebootcharacteristicifthecontrolvariableis
set,byclickingabuttonthatwewillsoonimplement.Wecanoverrideanothermethodin
bleGattCallback:
@Override
publicvoidonCharacteristicWrite(BluetoothGattgatt,
BluetoothGattCharacteristiccharacteristic,intstatus){
isSendReboot=false;
readNextCharacteristic(gatt,characteristic);
super.onCharacteristicWrite(gatt,characteristic,status);
}
Thismethodiscalledwheneverthewritecharacteristicoperationsucceedswhenwereset
ourcontrolvariableandcontinuewiththereadoperations.Thoseofyouwhoare
observantmightseeaminorproblemwiththiscode,namelythatwearesendingareboot
commandtothePi,butatthesametime,we’realsotryingtoreadcharacteristicsfromthe
Bluetoothdevicelocatedonthesamedevicethatwearetryingtoreboot.Thesereadings
willnotworkwhenthePireboots,andourappwillnotbeabletoreconnectifwedonot
closeandreopenitafterthereboothasbeencompletedsuccessfully.Thesolutiontothis
issuewillbeleftasanexerciseforyou.
Thelastpartoftheimplementationistoaddabuttonforthecommandtoouruser
interfaceandconnectthisbuttontoamethodintheMainAcitivity.javafilewhichwill
beexecutedwheneverthebuttonispressed.Addthefollowinglinestothe
activity_main.xmlfileinsidetheRelativeLayouttagtobeginwith:
<Button
android:id="@+id/reboot_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/humidity_textview"
android:text="Reboot"
android:onClick="sendRebootCommand"
android:enabled="false"/>
DefinethesendRebootCommandmethodintheMainActivity.javafile:
publicvoidsendRebootCommand(Viewv)throwsInterruptedException
{
isSendReboot=true;
}
TheonlythingthisfunctiondoeswhentheRebootbuttonisclickedonissetthecontrol
variablethatwehavedefinedpreviously.
YoucanalsoaddthefollowingcodeintheonScanResultmethodoftheScanCallback
classinstanceafterthecalltothedevice.connectGattmethodtoenablethebuttonwhen
weconnecttoRaspberryPiviaBluetooth:
if(bleGatt!=null){
MainActivity.this.findViewById(R.id.reboot_button).setEnabled(true);
}
ThisisagoodplacetotesttheappagainandseeifyoucansuccessfullyrestartthePi
throughanAndroiddevice.
Sendingmorecommandsfromyour
AndroidphonetothePi
Intheprevioussection,wehavesenttherebootcommandfromAndroidtothePi.Inthis
section,wewillsendtwonewcommands.OnetolightupaLEDthatwewillconnectto
thePi,andanothertoplaysoundonthePi.Thesecommandswillbereusedinthe
forthcomingsections.
LightingtheLEDs
We’llbeginbyconnectingaLEDlighttotheGPIOportsofthePi.TheLEDsusually
comewithashortandlongleg.ConnectaresistortotheshortlegoftheLED,andconnect
afemale/femalejumpertotheothersideoftheresistor.Thisjumpershouldthenbe
connectedtooneofthegroundpinsofthePi.TakealookattheschemainChapter2,
ServerManagementwithPi,toidentifythepins.Notethatwealreadyusedoneofthe
groundpinswhenweconnectedourtemperature-humiditysensortothePi.However,
thereareplentyofgroundpinsavailable.ThelonglegoftheLEDshouldbeconnectedto
oneoftheGPIOpins.Wewillchoosenumber17.YoucantakealooktheGPIOport
mappingsdiagraminChapter2,ServerManagementwithPi,toidentifyport17.
Tip
Itisagoodideatochoosearesistorinthespanof270Ωto470Ω.Thisresistortoprotects
theLEDlampfromunexpectedvoltagechanges.Ifyouchoosearesistorwithlowerohm
values,thentheLEDwillbebrighter.
WewillaccesstheGPIOandLEDlampusingasoftwareutilitycalledwiringPi.Wecan
downloadandinstallitusingthefollowingcommands:
cd
gitclonegit://git.drogon.net/wiringPi
cdwiringPi
./build
Thesecommandshavehelpedustoinstallacommand-linetoolcalledgpio,whichyou
cannowusetolighttheLEDlamp:
gpio-gmode17out
gpio-gwrite171
Youcanturnitoffusingthefollowingcomand:
gpio-gwrite170
WeneedtoaddtwonewcharacteristicstoourBLEserverimplementation:thefirsttoturn
thelighton,andthesecondtoturnitoff.Addthefollowinglinestotheendofthe
sensor.gofile,andnotethatwehavenewUUIDsforeachnewcharacteristicthatwe
create:
s.AddCharacteristic(gatt.MustParseUUID("51fac9e0-c111-11e3-92460002a5d5c51b")).HandleWriteFunc(
func(rgatt.Request,data[]byte)(statusbyte){
log.Println("Commandreceivedtoturnon")
exec.Command("sh","-c","gpio-gmode17out").Output()
exec.Command("sh","-c","gpio-gwrite171").Output()
returngatt.StatusSuccess
})
s.AddCharacteristic(gatt.MustParseUUID("61fac9e0-c111-11e3-92460002a5d5c51b")).HandleWriteFunc(
func(rgatt.Request,data[]byte)(statusbyte){
log.Println("Commandreceivedtoturnoff")
exec.Command("sh","-c","gpio-gmode17out").Output()
exec.Command("sh","-c","gpio-gwrite170").Output()
returngatt.StatusSuccess
})
Now,buildandrestarttheBLEserveragain.IfyouhaveaddedtheBLEservercommand
insidethecrontab,youmightneedtorebootthePi.Next,connecttothePiusingtheBLE
ScannerappagainandusetheWritebuttononcharacteristicssectionintheapptowrite
valuestothesecharacteristics.Youwillneedtoprovidesometexttowriteto,otherwise,
theBLEScannerappwillnotsendcommands.Onceyoudothis,youwillbeabletoturn
theLEDonandoff.
Tip
Itisalwaysagoodideatocheckthenewcharacteristicsyou’veaddedinBLEScanner
appbeforeyoutrytoaccessitwiththeappthatwearebuilding.Thisway,wecanbesure
thatwehaveaddedthecharacteristicscorrectlyonthePiside.
Thenextstepistoimplementthisnewfunctioninourapp.Wecanbeginbyintroducing
twonewbuttonsintheactivity_main.xmlfile:
<Button
android:id="@+id/turnon_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/reboot_button"
android:text="Turnon"
android:onClick="sendTurnOnCommand"
android:enabled="false"/>
<Button
android:id="@+id/turnoff_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/turnon_button"
android:text="Turnoff"
android:onClick="sendTurnOffCommand"
android:enabled="false"/>
InMainActivity.java,definethenewUUIDandcontrolvariablesforthenew
characteristics:
privatestaticfinalUUIDUUID_TURNON=
UUID.fromString("51fac9e0-c111-11e3-9246-0002a5d5c51b");
privatestaticfinalUUIDUUID_TURNOFF=
UUID.fromString("61fac9e0-c111-11e3-9246-0002a5d5c51b");
privatevolatilebooleanisSendTurnOn=false;
privatevolatilebooleanisSendTurnOff=false;
IntheonScanResultmethodofscanCallback,addthefollowingcodeintheif-statement
toenablethesetwobuttonsjustafterenablingtherebootbutton:
MainActivity.this.findViewById(R.id.turnon_button).setEnabled(true);
MainActivity.this.findViewById(R.id.turnoff_button).setEnabled(true);
IntheonCharacteristicReadmethodofbleGattCallback,addnewelse-ifstatementsto
theexistingcheckofthecontrolvariableforisSendReboot.Thenewcodewilllook
similartothefollowing:
if(isSendReboot){
BluetoothGattCharacteristicrebootCharacteristic=
service.getCharacteristic(UUID_REBOOT);
rebootCharacteristic.setValue("reboot");
gatt.writeCharacteristic(rebootCharacteristic);
}elseif(isSendTurnOn){
BluetoothGattCharacteristicturnOnCharacteristic=
service.getCharacteristic(UUID_TURNON);
turnOnCharacteristic.setValue("turnon");
gatt.writeCharacteristic(turnOnCharacteristic);
}elseif(isSendTurnOff){
BluetoothGattCharacteristicturnOffCharacteristic=
service.getCharacteristic(UUID_TURNOFF);
turnOffCharacteristic.setValue("turnoff");
gatt.writeCharacteristic(turnOffCharacteristic);
}else{
readNextCharacteristic(gatt,characteristic);
}
IntheonCharacteristicWritemethod,addthefollowingcodesnippettoresetthe
controlvariables:
isSendTurnOn=false;
isSendTurnOff=false;
Finally,addnewfunctionsthatcanbecalledonclickeventsforthenewbuttons:
publicvoidsendTurnOnCommand(Viewv)throwsInterruptedException
{
isSendTurnOn=true;
}
publicvoidsendTurnOffCommand(Viewv)throwsInterruptedException
{
isSendTurnOff=true;
}
Yourappwilllooksimilartothefollowingscreenshot:
Thefinalversionoftheapp
Bepatienttoseetheeffectsofthenewbuttonsafterclickingonthemasitwilltakeafew
secondsforthemessagestoarriveinthePi,andforthetheLEDlamptobeturnedon.
PlayingsoundsonyourPi
TobeabletoplaysoundsonthePi,soundmodulesshouldbeloadedonreboot.Todothis,
weneedtoaddsoundmodulespecificationstothe/etc/modulesfile.Addsnd-bcm2835
inthisfileifitdoesnotalreadyexistthere.
Tip
Youcanusethelsmodcommand-linetooltoseewhichmodulesareloadedatthemoment:
sudomodprobesnd_bcm2835
Thiscommandloadsthesoundmodulewithoutrebootingforthecontentsofthe
/etc/modulesfiletotakeeffect.
Weevenneedtofindanaudiofiletoplay,whichwecandownloadusingthefollowing
command:
cd
wgethttp://www.freespecialeffects.co.uk/soundfx/sirens/whistle_blow_01.wav
Youcannowplaythissoundusingthefollowingcommand:
aplaywhistle_blow_01.wav
Tip
NotethatthattheaudiochannelmightdefaultduetoHDMIoutputandyoumaynothear
anythingonyour3.5mmjack.Inthiscase,youcanrunthefollowingcommandtosetthe
defaultaudioplayertothe3.5mmjack:
amixercsetnumid=31
Thenextstepistoaddthenewwritecharacteristictothesensor.gofile,asshowninthe
followingcode:
s.AddCharacteristic(gatt.MustParseUUID("71fac9e0-c111-11e3-92460002a5d5c51b")).HandleWriteFunc(
func(rgatt.Request,data[]byte)(statusbyte){
log.Println("Commandreceivedtowhistle")
exec.Command("sh","-c","aplay/home/pi/whistle_blow_01.wav").Output()
returngatt.StatusSuccess
})
DonotforgettobuildandrestartthePiusingthegobuildexamples/server.go
command.Next,defineanewbuttonintheactivity_main.xmlfile:
<Button
android:id="@+id/whistle_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/turnoff_button"
android:text="Whistle"
android:onClick="sendWhistleCommand"
android:enabled="false"/>
DefineaneweventhandlerfortheonClickeventintheMainActivity.javafile:
publicvoidsendWhistleCommand(Viewv)throwsInterruptedException
{
isSendWhistle=true;
}
Next,addnewtheUUIDandcontrolvariablestothesamefile:
privatestaticfinalUUIDUUID_WHISTLE=
UUID.fromString("71fac9e0-c111-11e3-9246-0002a5d5c51b");
privatevolatilebooleanisWhistle=false;
EnablethenewbuttonintheonScanResultmethodofthescanCallbackinstancevariable
insidetheif-statementforthebleGattnullcheck:
MainActivity.this.findViewById(R.id.whistle_button).setEnabled(true);
Addthefollowingcodeinthenewelse-ifstatementintheonCharacteristicReadhandler
forthebleGattCallbackvariable:
elseif(isSendWhistle){
BluetoothGattCharacteristicwhistleCharacteristic=
service.getCharacteristic(UUID_WHISTLE);
whistleCharacteristic.setValue("whistle");
gatt.writeCharacteristic(whistleCharacteristic);
}
AddanewstatementtoresetthecontrolvariableintheonCharacteristicWritemethod:
isSendWhistle=false;
Nowthewhistlecommandisreadytobetestedfromourapp.
Combiningthecommandsandbeinginformedon
incomingcalls
Inthislastsection,wewillcombinethewhistleandLEDlightupcommandsandinitiate
thisnewcommandwheneverourphonerings.Bynow,weareusedtocreatingnew
characteristics.Hereisanewonetobeaddedtosensor.gofile:
s.AddCharacteristic(gatt.MustParseUUID("81fac9e0-c111-11e3-92460002a5d5c51b")).HandleWriteFunc(
func(rgatt.Request,data[]byte)(statusbyte){
log.Println("Commandreceivedtoturnonandwhistle")
exec.Command("sh","-c","aplay/home/pi/whistle_blow_01.wav").Output()
exec.Command("sh","-c","gpio-gmode17out").Output()
exec.Command("sh","-c","gpio-gwrite171").Output()
returngatt.StatusSuccess
})
Wecancombinethesetwocommandstosaveourselvesfromthedevelopmentdetailsof
sendingtwoseparatecommandsasasingletransaction.Weneedanewpermissioninthe
AndroidManifest.xmlfiletogetanincomingcallstatefromtheAndroidsystem:
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>
WealsoneednewinstancevariablesinMainActivity.java:
privatestaticfinalUUIDUUID_WHISTLE_AND_TURNON=
UUID.fromString("81fac9e0-c111-11e3-9246-0002a5d5c51b");
privatevolatilebooleanisSendWhistleAndTurnOn=false;
Then,weneedtogetaninstanceofasystemphoneserviceandattachourownlistenerto
it.AddthesetwolinesofcodeintheonCreatemethod:
TelephonyManagerTelephonyMgr=(TelephonyManager)
getSystemService(Context.TELEPHONY_SERVICE);
TelephonyMgr.listen(newPhoneListener(),
PhoneStateListener.LISTEN_CALL_STATE);
Next,definealocalPhoneListenerclass:
classPhoneListenerextendsPhoneStateListener{
publicvoidonCallStateChanged(intstate,StringincomingNumber){
super.onCallStateChanged(state,incomingNumber);
switch(state){
caseTelephonyManager.CALL_STATE_RINGING:
Toast.makeText(getApplicationContext(),incomingNumber,
Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(),"CALL_STATE_RINGING",
Toast.LENGTH_LONG).show();
isSendWhistleAndTurnOn=true;
break;
default:
break;
}
}
}
Here,wheneverwegetastatechangeonthephone,wecheckifthisisa
CALL_STATE_RINGINGstate.Ifitis,wecansetthecontrolvariableforthenewlycreated
commandinthesamewayasthebuttonclickeventhandlersdidforpreviouslydefined
commands.Then,wecanaddthisadditionalelse-ifstatementintheonCharacteristic
readmethodaswell:
elseif(isSendWhistleAndTurnOn){
BluetoothGattCharacteristicwhistleAndTurnOnCharacteristic=
service.getCharacteristic(UUID_WHISTLE_AND_TURNON);
whistleAndTurnOnCharacteristic.setValue("whistleturnon");
gatt.writeCharacteristic(whistleAndTurnOnCharacteristic);
}
Next,we’llresetthecontrolvariableintheonCharacteristicWritemethodasfollows:
isSendWhistleAndTurnOn=false;
Now,youwillbeabletoseetheLEDlampturnedonandhearthewhistlesoundonthePi
assoonasyourphonerings.Notethatourappneedstobestartedandvisibleforthisto
work.Thisiscausedbyoneofthetwomainissueswiththecodewehave.Allthe
communicationwiththePithroughBLEshouldactuallybedoneinsideanAndroid
service,andphoneeventsneedtobehandledinsideBroadcastReceiverinsteadofinan
activity.Bothoftheseimplementations,thatis,Picommunicationandphonestate
interception,shouldactuallybeseparatedfromtheactivity.Anactivityshouldactuallybe
aUIcomponentandnothingmore.However,ourintentionherewastoshowyouonlythe
funpartsandbequickanddirty.ThesefurtherimprovementsontheAndroidcodewillbe
leftasanexerciseforyou.
Summary
Inthischapter,wecoveredalotofcontent,rangingfromBLEimplementationsonthePi
todetailsoftheAndroidBLEcode.WehadgreatfunwiththePiandcameupwitha
usefulprojectthatcanbedevelopedfurther.
Inthenextchapter,wewilllearnmorewaystomakeuseofBLEequipmentonthePiand
useourphonesnotjustasAndroiddevices,butalsoasaccesspointsforthePi.
Chapter6.TheVehiclePi
WewillcontinuetouseBluetoothonourPiinthischaptertotrackthelocationanddata
fromourcar.Thefollowingsectionswillbecoveredinthischapter:
Findingoutthelocationofthecar
UsingyourAndroiddeviceasanaccesspoint
Collectingthecardata
Sendingdatatothecloud
Puttingitalltogether
Findingoutthecarlocation
Inthischapter,wewillcollecttheenginedatafromourcar,butthingswillgetmore
excitingifwecangathersomeforoflocationdataaswell.Forthispurpose,wewill
connectaUSBGPSreceivertothePiandreceiveourlocationthroughthispieceof
equipment.Wewilluseoneofthecheapestreceiversavailableinthemarket,asshownin
thefollowingimage:
TheGlobalsatBU-353GPSreceiver
AfterconnectingtheGPStothePi,youcanissuethelsusbcommandtoseeifitis
registeredcorrectly.Theoutputfromthiscommandonmysystemisasfollows,andhere
ProlificistheGPSadapter:
Bus001Device002:ID0424:9514StandardMicrosystemsCorp.
Bus001Device001:ID1d6b:0002LinuxFoundation2.0roothub
Bus001Device003:ID0424:ec00StandardMicrosystemsCorp.
Bus001Device004:ID148f:5370RalinkTechnology,Corp.RT5370Wireless
Adapter
Bus001Device005:ID067b:2303ProlificTechnology,Inc.PL2303Serial
Port
Bus001Device006:ID0a5c:21e8BroadcomCorp.
ThenextthingweneedtoinstallisaGPSdaemonthatreceiveslocationinformationfrom
theadapter:
sudoapt-getinstallgpsdgpsd-clientspython-gps
Youmightneedtorebootinordertogetthedaemontostart.Otherwise,youcanissuethe
followingcommandtogetitworkingimmediately:
sudogpsd/dev/ttyUSB0-F/var/run/gpsd.sock
TheinstallationscripthasevenprovideduswithatooltoseethecurrentGPSlocationand
thesatellitesthatareinrangethroughatext-basedwindow:
cgps–s
Tip
TheGPSreceiverworksbestoutdoorsorwithaclearviewoftheskynearawindow.
Theoutputonmysystemandinmylocationfromthecgpscommandisshowninthe
followingscreenshot:
Theoutputfromthecgps–scommand
Here,youcanseetheGPSsatellitesthatI,inparticular,haveinmyview,andmylatitude
andlongitudeaswellasotherusefulinformationthatisavailablethroughtheGPSsystem.
Tip
Ifyougetatimeouterrorfromthecgpscommand,youneedtorestarttheGPSdaemon
usingthefollowingcommands:
sudokillallgpsd
sudogpsd/dev/ttyUSB0-F/var/run/gpsd.sock
IfyougetthistimeouteventhoughyouhaverebootedthePi,thenyoucanputthe
followingcommandsincrontab,but,thereisevenabetterplacetoputthese,whichwill
bedescribedlateron:
@rebootsudokillallgpsd
@rebootsudogpsd/dev/ttyUSB0-F/var/run/gpsd.sock
ItispossibletogetthelocationinformationprogrammaticallyfromPythonaswell.We
willmakeuseofthispossibilitylateron.Butfornow,thefollowingPythoncodeinafile
namedgetgps.pytotestthePythongpslibrary:
#!/usr/bin/python
fromgpsimport*
importmath
gpsd=gps(mode=WATCH_ENABLE)#startingthestreamofinfo
count=0
whilecount<10:#waitmax50seconds
gpsd.next()
ifgpsd.fix.latitude!=0andnotmath.isnan(gpsd.fix.latitude):
printgpsd.fix.latitude,gpsd.fix.longitude
break
count=count+1
time.sleep(5)
TheonlythingthistinyprogramdoesistooutputtheGPSlocationwheneverthereisone
toreport.Wecancallitusingthepythongetgps.pycommand.
Collectingthecardata
Forthepurposeofcollectingthecardata,wewilluseastandardOn-boarddiagnostics
(OBD)interfacefoundonmostcarsandreferredtoasOBD-IIorEOBDinEurope.These
areequivalentstandardsusedtoconnecttotheOBDportofthecar;youcanalsoread
diagnosticsdataandfaultcodesaboutthecarfromthisport.
Note
In1996,theOBD-IIspecificationwasmademandatoryforallcarsmanufacturedandsold
intheUnitedStates.TheEuropeanUnionfollowedsuitin2001bymakingEOBD
mandatoryforallgasoline(petrol)vehiclessoldintheEuropeanUnion,followedbyall
dieselvehiclesin2003.In2010,theHDOBD(heavyduty)specificationwasmade
mandatoryforcertainselectcommercial(non-passengercar)enginessoldintheUnited
States.EvenChinafollowedsuitin2008,andbythen,somelightvehiclesinChinawere
requiredbytheEnvironmentalProtectionAdministrationOfficetoimplementOBD.
Onmostcars,theOBDinterfaceisfoundunderthesteeringwheel.OnaToyotaAygo
from2008,itisfoundontheright-handsideunderthesteeringwheel.Somecar
manufacturersdonothavestandardportconnections.So,youmighthavetobuyanextra
OBDconvertercable.Theportinthecarlookslikethis:
TheOBDconnectioninthecar
WewillconnectanELM327-BluetoothsendertothisOBDconnectionandtheBluetooth
donglefromthepreviouschaptertothePiandmakethetwocommunicate.TheELM327
isaprogrammedmicrocontrollerproducedbyELMElectronicstotranslatetheon-board
diagnostics(OBD)interface.TheELM327commandprotocolisoneofthemostpopular
PC-to-OBDinterfacestandardsimplemented.Youcanbuyoneofthesepiecesof
hardwareinanypricerangewithdifferentpropertiesonAmazon.TheonethatIhaveis
byGoliton:
TheELM327-OBDBluetoothsender
TheeasiestwaytogetdatafromacaristouseanapponAndroidthatcantranslatethe
dataforyou.SearchforOBDonthePlayStore,andyouwillfindlotsofgreatappsthat
canconnecttoELM327andshowyouallthedetailsofyourcardata.However,wewant
tohavealotmorefunthanthis.
GettingthecardatatothePi
TocollectcardatafromthePiusingPythonviaBluetooth,weneedtoinstallsometools.
RunthefollowingupdatecommandtodownloadBluetooth-relatedpackages.NotethatI
amassumingthatyouhaveanewRaspbianinstallation.Samepackageshavebeen
installedinpreviouschaptersaswell:
sudoapt-getinstallbluetoothbluez-utilsbluemanpython-serialpythonwxgtk2.8python-wxtoolswx2.8-i18nlibwxgtk2.8-devgit-core--fix-missing
Tip
Youaremostprobablysittinginyourcarandworkingrightnow.Ifyouarestrugglingto
figureouthowtoconnecttotheInternet,youcanalwaysuseyourAndroiddeviceasa
hotspotandconnecttotheInternetusingtheWi-Fidonglethatweneedforthischapter
lateronanyway.
ConnectingthePitoaWi-Finetworkwascoveredpreviously,butletsremindourselves
abouthowitworks.
Addthefollowinglinestothe/etc/wpa_supplicant/wpa_supplicant.conffile.You
needtohaveconfiguredthehotspottoapplytheWPAPSKsecurityinsteadofPSK2:
network={
ssid="YOUR_NETWORKID_FOR_HOTSPOT"
psk="YOUR_PASSWORD_FOR_HOTSPOT"
}
Now,rebootthePi,andafterafewminutes,youwillseethatitisautomaticallyconnected
tothehotspotontheAndroiddeviceinthehotspotsettingswindow.
Onceagain,wecanusethelsusbcommandtolisttheconnectedUSBdevices.Theoutput
onmysystemisshownasfollows:
Bus001Device002:ID0424:9514StandardMicrosystemsCorp.
Bus001Device001:ID1d6b:0002LinuxFoundation2.0roothub
Bus001Device003:ID0424:ec00StandardMicrosystemsCorp.
Bus001Device004:ID148f:5370RalinkTechnology,Corp.RT5370Wireless
Adapter
Bus001Device005:ID067b:2303ProlificTechnology,Inc.PL2303Serial
Port
Bus001Device006:ID0a5c:21e8BroadcomCorp.
The005deviceistheBluetoothdonglethatIamreusingfromtheprevioussection.Issue
thehcitoolscancommandtoseeifyoucanreachtheOBDBluetoothdeviceconnected
tothecar:
Scanning…
00:1D:A5:15:A0:DCOBDII
YoucanseetheMACaddressoftheOBDdeviceaswell;writeitdownasitwillbeused
later.
Tip
Ifyougetintoproblems,suchasscanningorreachingtheOBD,youcanusethefollowing
commandstoseethestatusoftheconnectedBluetoothdongleandthebluetoothservice
onthePi:
hciconfighci0
/etc/init.d/bluetoothstatus
Let’stakealookatthefollowingcommand:
/etc/init.d/bluetoothrestart
Theprecedingcommandisusedtorestartthebluetoothservice.
Now,weneedtogivethepiuseraccesstotheBluetoothdevice.Editthe/etc/groupfile,
findtherowcontainingthebluetoothtext,andaddpitotheendofthisrow.Itneedsto
looksomethingsimilartobluetooth:x:113:pi.
WecannowconnectthePi’sBluetoothdongletotheOBDBluetoothdeviceusingthe
rfcommcommand.Thiscommandshouldbethefirstthingyouexecutebeforeconnecting
toOBD.YoucanhangupbeforecontinuingusingtheCtrl+Ckeycombination:
sudorfcommconnecthci000:1D:A5:15:A0:DC
Here,youshouldusetheMACaddressofyourownODBBluetooth,whichwefoundout
previouslyusingthehcitoolscancommand.
Now,issuethefollowingBluetoothpairingcommandtopairthePiwithOBDandusethe
MACaddressofOBD:
sudobluez-simple-agenthci000:1D:A5:15:A0:DC
ThePINisusuallyeither0000or1234:
RequestPinCode(/org/bluez/2336/hci0/dev_00_1D_A5_15_A0_DC)
EnterPINCode:1234
Release
Newdevice(/org/bluez/2336/hci0/dev_00_1D_A5_15_A0_DC)
Weshouldevenaddthedbusconnectionsupportbeforewecontinuetothenext
command:
sudoupdate-rc.d-fdbusdefaults
sudoreboot
MaketheOBDdevicetrustedbythePiinordertoskipmanualpairingthenexttimeusing
thefollowingcommand:
sudobluez-test-devicetrusted00:1D:A5:15:A0:DCyes
Tip
Thefollowingcommandwillletyoutesttheconnectionifyouhaveanyproblems.
ReplacetheMACaddresswithyourOBDadapter’sMACaddress:
sudol2ping00:1D:A5:15:A0:DC
Wewilluseatool,calledpyOBD-pi,toaccessthedatathattheOBDdonglemakes
available.Downloadandstarttheloggerusingthegitcommand.Thisisamore
developer-friendlyversionofawell-knownlibrarylocatedat
https://github.com/peterh/pyobd:
gitclonehttps://github.com/Pbartek/pyobd-pi
cdpyobd-pi
sudopython./obd_recorder.py
Tip
Donotforgettoturnyourignitionon.Also,don’tforgettoconnectviaBluetoothusing
theupcomingcommand.Itisagoodideatoputthisincrontab,otherwise,you’llneedto
useiteverytimeyourebootthePi:
sudorfcommconnecthci000:1D:A5:15:A0:DC&
Thecommandwillsavethedatatraffictothelogdirectory.Ifyougeterrorsregarding
0100response:CANERROR,thenyouhaveproblemswithprotocolselections,andyou
simplyneedtoedittheobd_io.pyfileandfindthefollowingline:
self.send_command("0100")
Then,addthefollowinglinesofcodejustbeforeit:
self.send_command("ATSP0")#selectautoprotocol
wx.PostEvent(self._notify_window,DebugEvent([2,"ATSP0response:"+
self.get_result()]))
Inthisway,wehaveforcedthecommunicationprotocoltobechosenautomatically.
Tip
Youmaywanttoruntheinitserverscriptonreboot.Youcannotputitincronbtabasthe
BluetoothorGPSmightnotbereadywhenitisrun.Putthecommandsattheendof
/etc/rc.localfilebeforetheexitline,instead:
sudokillallgpsd
sudogpsd/dev/ttyUSB0-F/var/run/gpsd.sock
sudorfcommconnecthci000:1D:A5:15:A0:DC&
UsingyourAndroiddeviceasanaccess
point
Wewillsendthedatawehavegatheredsofartoalocationonacloud,butweneedto
connectthePitotheInternetbeforewedothis.MakinganAndroiddeviceanInternet
accesspointorahotspotistrivialandcanbedonefromthesettingsofadevice.Wecan
thenconnectthePitothisnetworkthatAndroidprovides.However,thereisamajor
problemwiththissetup.Firstofall,wewanttobeabletoleavethePiandthephonein
thecarallthetime.Assoonasthecarstarts,wewantthedatatobesentautomatically,
andwedonotwanttocarryaroundthePiandaphone.However,ifweleavethephonein
thecaranditisconnectedtothe12Vpoweroutput,thedevicewillsoonrunoutofbattery
andshutdown.Then,we’llneedtopoweritonmanuallyandmakechangesinthehotspot
settingsagain.Wewantallthesestepstobeundertakenautomatically.Forthisreason,we
needawaytogetthedevicepoweredonassoonasitisconnectedtoapowersource,or
thepowersourceitisconnectedto,suchasa12Vpoweroutputinthecar,wakesupwhen
westartthecar.ThetechniquesIwillnowpresentrequirethatyouhavesuperuser
privilegestoyourAndroiddevice,whichmeansthatweneedtorootthedevice.
Analternativetorooting
AnalternativetorootingadeviceisusingaUSBWi-Fi3GmodemtogetInternetaccess
inthecar.Notethatmostofthe3GUSBmodemsinthemarketdonotprovideyouwitha
Wi-Finetwork.Theyonlygivenetworkaccesstothecomputerintowhichtheyare
plugged.TheoneweneedactssimilartoaWi-FihotspotwhenconnectedtoaUSBpower
source.Youcanfindtheseatonlineretailers,suchasAmazonorAliExpress.TheoneI
personallyuseisshowninthefollowingimage:
TheUSBWi-Fi3Gmodem
Ifyouchoosetouseoneofthese,youmayjumpovertherestofthissectionandgo
directlytothenext.
RootingSamsungGalaxyS2
Therearedifferentwaysofrootingdifferentdevices.Iwilluseoneofthemostcommon
secondhandAndroiddevicesinthemarket,namely,SamsungGalaxyS2.Ifyouhave
anotherphone,thereareplentyofresourcesavailableontheInternetonhowtorooteach
device.Themostpopularoneislocatedathttp://www.androidcentral.com/root,the
AndroidCentralwebsite.
Note
Notethatrootingadevicewillmaketheguaranteeinvalid.Thismaycausedamageto
yourphoneandisnotasecureprocess.Doitonyourownrisk.Butthestepsprovided
hereworkedforme.Youshouldbackupanyfilesyouwouldliketokeepbeforeyou
continuewiththerestofthischapter.
Samsungdevicescanbeputintorecoverymodebypressingthevolumedown,power,
homebuttonsatthesametime.Bypressingthesebuttons,youwillgetSamsung’s
standardrecoveryscreenwithawarningsignonit.Weshouldreplacethisrecovery
programwithanotherone,asthestandardrecoveryisonlytobedonethroughacomputer
connectedviaaUSBanddownloadsacompleteOSimage.However,whatwereallyneed
todoisonlyreplaceakernelwithonethatgivesussuperuserrights.Wealsowantto
makesurethatwedothisfromanSDcardattachedtoanAndroiddevice.Thatiswhywe
needtoreplaceSamsung’sdefaultrecoveryprogram.Wecandothisagainusingthe
recoveryoperationprovidedbySamsung.
Whenyouputthedeviceinthisrecoverymode,attachittoacomputerthroughaUSB.
Next,wecandownloadasoftware,namedOdin,touploadanewrecoverytooltothe
phone.ItcanbedownloadedfromquitealotofplacesontheInternetalongwithdifferent
versions.TheonewewilluseiscalledODIN3_v1.85.zip,anditislocatedat
https://www.androidfilehost.com/?fid=9390169635556426736.Anotherfileweneedisa
kerneltoreplacetheexistingonethatwillhelpuswithnewwaysofrecoveryoperations.
ThisfileisnamedJebooKernel,andcanbefoundat
http://downloadandroidrom.com/file/GalaxyS2/kernels/JB/jeboo_kernel_i9100_v1-2a.tar.
Asinstructedontherecoveryscreenonthephone,youshouldpressthevolumeupbutton
toputthedeviceinthedownloadmode.Then,startOdin,andselectthenewly
downloadedJebooKernelasPDA.YoushouldseeaCOMboxmarkedinyellowifthe
phoneiscorrectlyconnected,andisinthekerneldownloadmode:
OdinshowsJebooasPDAandaconnecteddeviceonCOM11.ClickonStarttoupload
uploadthenewJebookernelyouhaveselected.
ItshouldnottaketoomuchtimebeforeyougetaPASSnotification:
Odinhasbeencompletedsuccessfully
Now,yourphoneshouldreboot,andyoushouldseeawarningtriangleontherestart
screen,indicatingthatyouhaveanewkernelwiththe“recoveryfromSDcard”feature.
ThenextstepistosavetheCWMSuperUserfilefrom
http://downloadandroidrom.com/file/tools/SuperSU/CWM-SuperSU-v0.99.ziptotheSD
cardandattachittothedevice.Now,poweroffyourdeviceandputitintorecoverymode
againthistimeusingaslightlydifferentkeycombination,thatis,volumeup,power,home.
Notethatwepressvolumeupinsteadofvolumedownaswedidbefore.Youwillseea
differentrecoveryscreencalledCWM-basedRecovery.Youcanscrollupanddown
usingthevolumeupandvolumedownkeys.SelecttheInstallZipitemusingthehome
button,andthentheChoosefromSDcardoption.YoushouldbrowsetotheCWMSuper
UserZIPfilethatyouhavedownloadedontotheSDcard.Finally,chooseYes.
Rebootthedevice,andyouwillseeanewappcalledSuperUser,whichindicatesthat
youhavesuccessfullyrootedyourdevice.Youcanevenverifythatyouhavesuperuser
accesstoyourdevicebydownloadingoneoftheSuperUsercheckerappsonGooglePlay.
YouwillseeamessageboxaskingyouaquestionfromtheSuperUserapp,thatwehad
installedfromthepreviousstep,ifyouwanttograntsuperuserprivilegestoanyotherapp
askingtogetthose.
Enablingtetheringonbeingconnectedtoapower
source
Asourphonehypotheticallystaysinthecarallthetime,andonlygetspoweredupwhen
thecarisbeingused,weneedtofindawaytoenableWi-Fitetheringorahotspot,asitis
aswellcalled,wheneverthephoneisconnectedtoapowersource.Therearetwocases
thatwemightencounter,though:
Thebatteryhasrunoutandthephoneisturnedoffatnight.Here,weneedtofinda
waytoturnonthephonewheneveritgetspoweredupagain.Thishappenswhenwe
startthecar.Whenthephoneissuccessfullyturnedon,weneedtofindawayto
enableahotspot.
Thephonestillhasenoughbatterytokeepitturnedon,butasithasn’tbeenused,the
hotspotisdisabled.Notethattheonlydeviceusingthephone’shotspotisthePiand
itisturnedoffifthecarisn’tbeingused.Whenwestartthecaragain,thephonegets
poweredupfromtheUSBcontact.Inthiscase,weneedtoenablethehotspotagain.
Automaticrestartonpowerconnect
WhenweconnectaturnedoffSamsungdevicetoapowersource,wewillseeagray
batteryimagewithaturningarrowinsideit.Then,whenitbeginschargingthebattery,we
willseeanothercoloredbatteryimageshowingthecurrentchargelevel.Thissecond
imageisgeneratedbyaprogramthatistriggeredwheneveraturnedoffdevicebegins
chargingthebattery.Itisabinaryfilelocatedin/system/bin/playlpmonthephone.We
willchangethisfiletoascriptofourowntorebootthedevice.Inordertobeabletoedit
thisfile,weneedsuperuserprivileges.Thisiswhywehaverootedthephone.Asan
AndroidsystemisactuallyaLinuxOSunderthehood,wecanrunanyLinuxcommand
onit.WecandothisusinganappthatwecandownloadfromthePlayStore,called
TerminalEmulator:
TheTerminalEmulatorappscreen
Now,issuetheupcomingcommandstochangethecontentsoftheplaylpmfileandmake
itanexecutablefile.Weneedtoalsoremountthe/systemdirectoryinordertoenableit
forwriteoperations:
mount-orw,remount/system
mvplaylpmplaylpmbackup
echo"#!/system/bin/sh">playlpm
echo"sleep60">>playlpm
echo"/system/bin/reboot">>playlpm
chmod0755/system/bin/playlpm
chownroot.shell/system/bin/playlpm
mount-oro,remount/system
Turnoffthedeviceandconnectittoapowersource.Youwillseethatitturnson
automaticallyafteroneminute.Wehaveintroducedtheoneminutedelaybecauseifthe
batteryistotallydischarged,itwillnothaveenoughcapacitytorestartthedevice.We
wanttowaitatleastoneminuteinthesekindsofsituationsforthebatterytogetcharged
enoughtorestartthedevice.Ifitisnotchargedsufficiently,youmightneedtochargeyour
phonebeforeitcanautomaticallyrestart.Youcanchargethephonewithoutgettingit
restartedbyputtingitintotherecoverymodeandthenbeginchargingit.
Autotethering
Nowweareabletorestartthedeviceonconnectingittoapowersource.Weneedtoalso
enabletetheringonthedevicewhenitwakesuporisconnectedtoapowersource.There
areappsonthemarketthatalreadydothis,butthebestonesarepaid.Thisisoneofthe
reasonsthatwewillimplementourownappforthispurpose.Theotherreasonisthatitis
fun.
WecancreateanewapplicationintheAndroidStudioaswedidbefore.Wewillnotneed
anyActivityforthisapplication.
Createanewjavafile,calledStartTetheringAtBootReceiver,forBroadcastReceiver
andaddthefollowingcodeinit:
publicclassStartTetheringAtBootReceiverextendsBroadcastReceiver{
publicstaticvoidsetWifiTetheringEnabled(booleanenable,Context
context){
WifiManagerwifiManager=(WifiManager)
context.getSystemService(Context.WIFI_SERVICE);
Method[]methods=
wifiManager.getClass().getDeclaredMethods();
for(Methodmethod:methods){
if(method.getName().equals("setWifiApEnabled")){
try{
method.invoke(wifiManager,null,enable);
}catch(Exceptionex){
ex.printStackTrace();
}
break;
}
}
}
@Override
publicvoidonReceive(Contextcontext,Intentintent){
if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())||
Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())){
setWifiTetheringEnabled(true,context);
}
}
}
Thispieceofcodereceivesbroadcasteventswheneverthephoneisbootedorconnected
toapowersource,andenablestetheringonthedevicewiththedefaultsettings.Ifwe’d
liketochangethenameofthenetworkorthepassword,we’llneedtomodifythesettings
onthedevice.
AddthemanifestdefinitionforthenewbroadcastreceivertoAndroidManifest.xml
insidetheapplicationtag:
<receiver
android:name=".StartTetheringAtBootReceiver"
android:label="StartTetheringAtBootReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
<actionandroid:name="android.intent.action.ACTION_POWER_CONNECTED"
/>
</intent-filter>
</receiver>
Addthefollowingpermissiondeclarationsinsidethemanifesttag:
<uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED"
/>
Now,installthisapptoyourphoneandseeifthetetheringisenabledwheneveryoureboot
thedeviceorconnectapowercabletoit.
WecanoptionallyaddashortcutbuttonfortetheringinMainActivity.Inthe
activity_main.xmlfile,addthefollowingbuttondefinition:
<Buttonandroid:text="@string/enable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"/>
Next,intheMainAcitivty.javafile,definethehandlerforthebutton:
publicvoidclick(Viewv){
StartTetheringAtBootReceiver
.setWifiTetheringEnabled(true,this);
}
Next,weneedtoconnectthePitothehotspotthatwehavecreatedsofar.Connectingthe
PitoaWi-Finetworkwascoveredearlier,butlet’sremindourselvesaboutthisconcept
again.Addtheupcominglinesofcodetothe
/etc/wpa_supplicant/wpa_supplicant.conffile.Wecanconfigurethehotspottoapply
WPAPSKsecurityinsteadofPSK2:
network={
ssid="YOUR_NETWORKID_FOR_HOTSPOT"
psk="YOUR_PASSWORD_FOR_HOTSPOT"
}
Now,we’llrebootthePi,andafterafewminutes,we’llseethatitisautomatically
connectedtoahotspotontheAndroiddeviceinthehotspotsettingswindow:
ThelistofconnecteddevicesisshowninhotspotsettingsinAndroid
Youmustbewonderingwhywehavecoveredthiscontentatthispoint.Thisisbecausein
ordertoimplementthenextsection,you’llmostprobablyneedtositinyourcarand
communicatewiththePiinsideyourcar,whereyoumostprobablydonothavemore
networkaccessthanthehotspotAndroidprovidesyouwith.Now,ifyouconnecttothe
samehotspotonAndroidfromyourcomputer,youwillbeabletoSSHtothePiwitha
toolcalledPuTTYthatyoucaninstallonWindowsmachinesorusingbuiltinSSH
terminaltoolonaMac.
Sendingdatatothecloud
WewilluseaGoogleDocsspreadsheettosavedataandaspecialPythonlibrary
developedforthispurpose.WebegindoingthisbycreatinganAPIkeytoaccessGoogle
services.
Browsetohttps://console.developers.google.com/projectandcreateanaccountforthis
purpose.Whenit’sready,youwillbedirectedtotheGoogleDeveloperConsole:
TheGoogleDeveloperConsolestartpage
Here,we’llneedtocreateanewprojectintheSelectaprojectdrop-downmenu.Giveita
suitablename,accepttheagreement,andclickonCreate.Selectthenewlycreated
project,APIs&auth,andthenselectAPIsfromthemenuontheleft-handside.Then,
findandselectDriveAPI,andpresstheEnableAPIbutton.Whenitisenabled,goto
Credentialsontheleft-handsidemenuunderAPIs&auth:
ThemenutoenableOAuthintheGoogleDeveloperConsole
Here,underOAuth,clickontheCreatenewClientIDbutton.Inthemessageboxthat
appears,selecttheServiceaccount,andclickontheCreateClientIDbutton.We’llseea
boxtellingusthatwehavesuccessfullycreatedNewpublic/privatekeypairforthe
project.We’llevenseethatthesitehassentusaJSONfilewithcredentialsinit.Forthe
dummyaccountIcreated,thecontentslookssimilartothis:
{
"private_key_id":"ed5a741ff85f235167015d99a1adc3033f0e6f9f",
"private_key":"-----BEGINPRIVATEKEY----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDM9YJ2otxwdhcL\nQJ8ipZO
uILkq9dzWDJJgtjSgFUXTJvjgzTDNa2WXGy9p9i4Wuzrj5OJli/M5dMWr\n+CVZCpsfV7Xt7iqk
eCEo0dN225HDiAXXMvWKhDsiofau0xLCTFLDnLZFWqAd55ec\naENYQKp6ZEc6dGaA7Kp7O1+7L
tEB2a4yqgZIelL6fTSSLQqyV477OS2Dkq+nz5Sz\nRyTexcDWioDNp2vdGadqDfRKsI7ELwgWsc
aV6jrbHz2uDuC844UnTL4WKMugp1n1\nObTuGDl1gldEIWlk2XSLFkGfY30lYV7XwrUQGgc85AG
RwdH7qYrQM3jO4D+6thAH\nETq4qjRRAgMBAAECggEAJjXXHrr6EdVSMnzXriPkRmA/ZSz1AMrT
N0iAwx90Jwtq\n9q4KXSGajPM6gaytpvs83WO8eWX/8EQ+3fKjM9hwVwWJG1R9irACrpN/svb4U
9W2\nEQqlEC/avngnfyxGoQaNn35F1OQyWaDlePlPJNLZdXvgc5tjyMFWfybwj/sIaCmR\nj5nt
V2aY/gCEbe6km7L/LkC3C7CesIWstUGMHCjh2aPeQT+Hpodf23AnLZuSo34j\nB+lSI/RjnDsd0
HfazOgaOXa/yK4SliTaMWUBiMSXQcwZZsVp/RL0Ve6W2PSfi092\n+hATaaRnA8zB8fx7PnAltP
hFwVr9+jjbYbq+wypoyQKBgQDoLJytaR4wof46MUiL\nMWrXDopi5dG2ofUSXR+JEIThe7yyYep
zzdWFL+rXNEzD5X9UcfCodwZ0PKLN3u0t\nZJ5Iq111bxwwZix5uVStRi6stgGaewF6nkDqN8y5
TJJgnZB9wSBuG3RvCU4zwXKZ\ngj2+azWme7PSyOHKNODbBd9DkwKBgQDh/e7nct49/Z0Om/+kN
J+NXUjka+S1yF7n\nhL+HZ2WU1gL8iQjXPxnCX1lThw7C4rForH/esOs+f1XMje8NYi7ggslqxo
XwFRH6\ny/tuCRaY+e62xmJAxj2o8InsvQQkSM+dtuZiaNq3gCatHKbx2C6SVQal/y3yuR0c\n0
0adgr6fCwKBgQDSlAvzGIFiWLsNqr+CR+sAbVbExm9EN3bhFgdROONc4+7M2BRe\nvlUoPMLCN9
RcZR3syH8fPP1klc6P7N6vqjAJ9yuIJKOrnjA+owKTOjGBQn8HzwMT\nZM+536xWcIXfDWoNNQo
l887SGt2MAavgYYmA2RpLCq2Zw8tOrFE5NgU+8wKBgQCe\nAiwNy3S0JySu2EevidOcxYJ3ozBw
IT6p5Vj81UBjBhdkdnOl+8qI6p3MFvwtKs8b\n/rARBeYU9ncI5Jwl4WYhN5CYhWGUcUb28bRER
Tp1jxpm1OJRo8ns2vG0gpvourfe\n78i5OdLixklEdGoNYjd9vNE/MuHveZpvUxFmg8m/7QKBgC
GVTkOXWLpRxuYT+M+M\n28LBgftHxu0YZdXx8mU9x6LQYG2aFxho7bkEYiEaNYJn51kdNZqzrIH
ebxT/dh/z\nddd5nR93E6WsPuqstZF4ZhJ+l2m77wmG9u5gfRifrNpc3TK0IswydFPIMNVxMz+d
\nl3cdqtiW6rvWSQoHC0brpcYL\n-----ENDPRIVATEKEY-----\n",
"client_email":"1490268255705eecriag0m9jbo50ohnt59sest5694d@developer.gserviceaccount.com",
"client_id":"1490268255705eecriag0m9jbo50ohnt59sest5694d.apps.googleusercontent.com",
"type":"service_account"
}
WecanchoosetogenerateanewkeyfromtheDeveloperConsolesiteusingtheGenerate
newJSONkeybuttonforourproject.
Atthisstage,weneedtogenerateaP12keyusingtheGeneratenewP12keybutton.
Thisfilewillbeusedlateron.Wewillalsobeprovidedwithasecretkeywhenwe
downloadthefilewhichweneedtonotedown.Thefollowingscreenshotillustratesthe
GoogleDeveloperConsoleaftersuccessfulcreationoftheAPIkey:
GoogleDeveloperConsoleaftersuccessfulAPIkeycreations
BeforewecaninstalltheGooglePythonlibrary,weneedtoinstallatool,calledpip,
whichwillhelpusinstallanOAuthclientwewillusetoconnecttoGoogleservices.Use
thefollowingcommandstodothis:
curl-Ohttps://raw.githubusercontent.com/pypa/pip/master/contrib/getpip.py
sudopythonget-pip.py
Then,usethisnewpiptooltoinstalltheOAuthclients:
sudoapt-getupdate
sudoapt-getinstallbuild-essentiallibssl-devlibffi-devpython-dev
sudopipinstall--upgradeoauth2client
sudopipinstallPyOpenSSL
ThenextstepistodownloadandinstalltheclientlibrarytoaccessGoogleSheetsonthe
Piusingthefollowingcommands:
gitclonehttps://github.com/burnash/gspread.git
cdgspread
sudopythonsetup.pyinstall
Beforewebegincoding,weneedtoaddanewspreadsheetonthehttps://docs.google.com
website.SelectSheetsinthemenu,createanewsheetusingtheplus(+)sign,andchange
thenamefromUntitledspreadsheettoCAR_OBD_SHEET.Itshouldbesaved
automatically.WeneedtosharethisspreadsheetwiththeGoogleDeveloperConsole
clientcreatedforuswhenwegeneratedtheOAuthkeypair.We’llfindaclient_email
fieldintheJSONfilewe’vedownloaded.Wewillsharethenewspreadsheetwiththis
client.Now,opentheCAR_OBD_SHEETspreadsheetinGoogleDocsandclickontheShare
button:
OpenthespreadsheetinGoogleDocs
Inthepop-upwindow,pasteclient_emailfromtheJSONfile,thenclickontheSend
buttononthepop-upwindow.Thiswillsharethespreadsheetwiththeclientgenerated
whenwecreatedtheOAuthkeypairinthepreviousstep:
Sharingthespreadsheetwiththegeneratedclient
Now,wewilltesttoseeifeverythingworksfine.CreateafileonthePi,nameit
send_to_sheet.py,andputthefollowingcontentinit.DonotforgettocreatetheOAuth
JSONfileandputthecontentsoftheonewehavedownloadedfromtheGoogle
DeveloperConsoleandnameitaspiandroidprojects.json:
importjson
importgspread
fromdatetimeimportdatetime
fromoauth2client.clientimportSignedJwtAssertionCredentials
json_key=json.load(open('piandroidprojects.json'))
scope=['https://spreadsheets.google.com/feeds']
credentials=SignedJwtAssertionCredentials(json_key['client_email'],
json_key['private_key'],scope)
gc=gspread.authorize(credentials)
t=datetime.now()
sh=gc.open("CAR_OBD_SHEET").add_worksheet(str(t.year)+"_"+
str(t.month)+"_"+str(t.day)+"_"+str(t.hour)+"_"+str(t.minute)+
"_"+str(t.second),100,20)
sh.update_cell(1,1,0.23)
Now,runthefileusingthepythonsend_to_sheet.pycommand,andwewillseethe
updateontheGoogleDocssheet.Thecodewillcreateanewworksheetnamedasthe
currenttimestampandsaveasinglevalueinthissheet.NotethatGoogleallows200
worksheetspersheet,andbydefault,100rowsperworksheet;inourcode,wecreatea
newworksheeteachtimewerunit.Weneedtocleanthesheetfromtimetotimeinorder
tonottogobeyondthelimit.
Puttingitalltogether
Inthenexttwosections,wewillputtogetherwhatwehavedonesofar.First,we’llbegin
bysendingdatatotheGoogleDocssheet.Then,wewillbuildanAndroidapptoshowthe
dataonamap.
Sendingmeasurements
WewilluseaPythonscripttoaccessGPSdataonthePithatwe’llneedtorunonsystem
reboot.Forthispurpose,addthefollowingcodeattheendofthe/etc/rc.localfile:
sudokillallgpsd
sudogpsd/dev/ttyUSB0-F/var/run/gpsd.sock
sudorfcommconnecthci000:1D:A5:15:A0:DC&
sleep1m
current_time=$(date"+%Y.%m.%d-%H.%M.%S")
file_name=/home/pi/log_sender.txt
new_filename=$file_name.$current_time
sudo/home/pi/pyobd-pi/sender.py>$new_filename2>&1&
Here,wecanrestarttheGPSservices,connecttotheOBDBluetoothdongle,createalog
file,andstartthesender.pyscriptthatwewillimplementnext:
#!/usr/bin/envpython
importobd_io
fromdatetimeimportdatetime
importtime
importthreading
importcommands
importtime
fromgpsimport*
importmath
importjson
importgspread
fromoauth2client.clientimportSignedJwtAssertionCredentials
gpsd=None
classGpsPoller(threading.Thread):
def__init__(self):
threading.Thread.__init__(self)
globalgpsd
gpsd=gps(mode=WATCH_ENABLE)
defrun(self):
globalgpsd
whileTrue:
gpsd.next()
classOBD_Sender():
def__init__(self):
self.port=None
self.sensorlist=[3,4,5,12,13,31,32]
defconnect(self):
self.port=obd_io.OBDPort("/dev/rfcomm0",None,2,2)
if(self.port):
print"Connectedto"+str(self.port)
defis_connected(self):
returnself.port
defget_data(self):
if(self.portisNone):
returnNone
current=1
while1:
cell_list=[]
localtime=datetime.now()
cell=sh.cell(current,1)
cell.value=localtime
cell_list.append(cell)
try:
gpsd.next()
except:
print"gpsd.next()error"
cell=sh.cell(current,2)
cell.value=gpsd.fix.latitude
cell_list.append(cell)
cell=sh.cell(current,3)
cell.value=gpsd.fix.longitude
cell_list.append(cell)
column=4
forindexinself.sensorlist:
(name,value,unit)=self.port.sensor(index)
cell=sh.cell(current,column)
cell.value=value
cell_list.append(cell)
column=column+1
try:
sh.update_cells(cell_list)
print"sentdata"
except:
print"update_cellserror"
current=current+1
time.sleep(10)
json_key=json.load(open('/home/pi/pyobd-pi/piandroidprojects.json'))
scope=['https://spreadsheets.google.com/feeds']
credentials=SignedJwtAssertionCredentials(json_key['client_email'],
json_key['private_key'],scope)
whileTrue:
try:
gc=gspread.authorize(credentials)
break
except:
print"ErrorinGoogleDocsauthorize"
t=datetime.now()
sh=
gc.open("CAR_OBD_SHEET").add_worksheet(str(t.year)+"_"+str(t.month)+"_"+str
(t.day)+"_"+str(t.hour)+"_"+str(t.minute)+"_"+str(t.second),100,20)
gpsp=GpsPoller()
gpsp.start()
o=OBD_Sender()
o.connect()
time.sleep(5)
o.connect()
time.sleep(5)
o.get_data()
Thecodebeginsrunningattheendwherewedefinejson_keybyloadingtheJSONkey
file.Then,we’lltrytoauthorizeusingthegspread.authorize(credentials)method.
Thenextstepistocreateanewworksheetwiththedatetimestampasthetitle,andthen
starttoconsumetheGPSdatainanotherthreaddefinedbytheGpsPollerclass.Next,
we’llinitiatetheOBD_SenderclassandconnecttotheODBBluetoothdevicetwice.The
connectoperationmayfailwhenit’sexecutedforthefirsttime,butitalmostalways
succeedswhenit’srunasecondtime.Then,weneedtoruntheget_datamethodofthe
OBD_Senderclasstobegintheloop.
TheGpsPollerclassconsumesallthevaluesoftheGPSdeviceconnectedtotheserial
USBport.Thisisrequiredinordertogetthemostrecentvalueswheneverweaccessthe
gpsd.fix.latitudeandgpsd.fix.longitudevariables.
Theget_datamethodoftheOBD_Senderclasssendsthelocaltime,latitude,andlongitude
valuestothespreadsheet,anditalsosendssevendifferentreadingsdefinedin
self.sensorlist=[3,4,5,12,13,31,32].WecanseethesevaluesfromtheSENSORS
listintheobd_sensors.pyfile.Foryourinformation,thesearetheFuelSystemStatus,
CalculatedLoadValue,CoolantTemp,EngineRPM,VehicleSpeed,EngineStartMIN,
andEngineRunMILvalues.Wecanchangetheindexestoreadthevaluesthatwewant.
Takealookatadditionalvaluesathttps://en.wikipedia.org/wiki/OBD-II_PIDs.Wego
throughthesecodes,readtheircurrentvalues,andsendthemtothedifferentcellsofa
currentrowonourworksheet.Afterstartinganddrivingyourcararound,youcanseethat
thedataisuploadedtothespreadsheet,asshowninthefollowingscreenshot:
Datauploadedtothespreadsheet
Retrievingmeasurements
Wewillbuildourveryownapptodownloadthemeasurementvaluesandshowthemona
map.CreateanewblankprojectintheAndroidStudio,andchoosetoincludeaGoogle
MapsActivityduringthelaststepofcreateprojectwizard.I’veusedAndroid4.3asthe
baseSDKforthisproject;IwillnamemymainactivityasMapsActivity.
ToaccessGoogleDocsanddownloadthecontentofthespreadsheet,wewillusesomeof
theJavalibrariesprovidedbyGoogle.Theyarelocatedatdifferentplaces.Downloadthe
ZIPfilesfromthefollowinglocations:
AgeneralpurposeJavaclientforGoogledataservicesislocatedat
https://github.com/google/gdata-java-client,andthefileisnamedasgdatasrc.java-*.zip,whichisfoundundertheSourcelink.
DownloadtheHTTPclientfromhttps://developers.google.com/api-clientlibrary/java/google-http-java-client/downloadwhichisnamedasgoogle-http-javaclient-featured.zip.Wewillusethistoauthorizeourselves.
DownloadtheOAuthclientcontainedingoogle-oauth-java-clientfeatured.zip,whichisavailableathttps://developers.google.com/api-clientlibrary/java/google-oauth-java-client/download
Now,opentheseZIPfiles,locatethefollowingJARlibraries,andmovethemtothelibs
folderunderyourAndroidappdirectory:
gdata-base-1.0.jar
gdata-core-1.0.jar
gdata-spreadsheet-3.0.jar
google-api-client-1.20.0.jar
google-http-client-1.20.0.jar
google-http-client-jackson-1.20.0.jar
google-oauth-client-1.20.0.jar
guava-11.0.2.jar
jackson-core-asl-1.9.11.jar
ToincludetheselibrariesinyourAndroidproject,youneedtoaddthemtothe
build.gradlefileforModule:app.Todothis,addthefollowingcodeunderthe
dependenciestag.
compilefiles('libs/gdata-spreadsheet-3.0.jar')
compilefiles('libs/gdata-core-1.0.jar')
compilefiles('libs/guava-11.0.2.jar')
compilefiles('libs/gdata-base-1.0.jar')
compilefiles('libs/google-http-client-1.20.0.jar')
compilefiles('libs/google-http-client-jackson-1.20.0.jar')
compilefiles('libs/google-api-client-1.20.0.jar')
compilefiles('libs/google-oauth-client-1.20.0.jar')
compilefiles('libs/jackson-core-asl-1.9.11.jar')
Whenyoueditthebuild.gradlefile,youmightgetamessageinAndroid,statingthat
Gradlefileshaschangedsincelastprojectsync.Aprojectsyncmaybenecessaryfor
theIDEtoworkproperly.ClickontheSyncNowlinklocatednearthisnotificationto
updatetheproject.
ThenextstepistomovetheP12keyfile,whichwehavedownloadedfromtheGoogle
DeveloperConsole,andincludeitinourAndroidproject.Weneedtocopythisfileinthe
rawdirectorylocatedatPROJECT_HOME\app\src\main\res\rawandrenameitas
piandroidprojects.p12.
Asweplantoshowthecontentonamap,wewilluseGoogle’sMapAPIforthispurpose.
Touseit,weneedanaccessAPIkey.Gotothedeveloperconsoleagainat
https://console.developers.google.com/project,andselecttheprojectthatwe’vecreated
previously.Inthemenulocatedontheleft-handside,chooseAPIsunderAPIS&auth,
then,GoogleMapsAndroidAPI,andfinally,clickontheEnableAPIbutton.Next,
navigatetoCredentials,andclickontheCreatenewkeybuttonunderthePublicAPI
accesssection.WeneedtochooseAndroidkeyinthewindowthatpopsup.Copythe
generatedAPIkeyandreplaceitwiththeYOUR_KEY_HEREstringinthe
google_maps_api.xmlfile.Now,wearereadywithourAndroidprojectsetup,anditis
timetocodenow.
ThefirstthingtodointhecodeisdownloadalistofsheetsfromGoogleDocs.Thereis
onesheetforeachrestartofthePi.AddthefollowingcodeinsidetheonCreatemethodof
theMapsActivity.javafile:
newRetrieveSpreadsheets().execute();
ThispieceofcodewillcreateanasynchronoustaskthatisimplementedasanAndroid
AsyncTask,whichdownloadsandpresentsthespreadsheets.Let’sdefinethetaskclassin
thesamefileaswell:
classRetrieveSpreadsheetsextendsAsyncTask<Void,Void,
List<WorksheetEntry>>{
@Override
protectedList<WorksheetEntry>doInBackground(Voidparams){
try{
service=
newSpreadsheetService("MySpreadsheetIntegration-v1");
HttpTransporthttpTransport=newNetHttpTransport();
JacksonFactoryjsonFactory=newJacksonFactory();
String[]SCOPESArray=
{"https://spreadsheets.google.com/feeds",
"https://spreadsheets.google.com/feeds/spreadsheets/private/full",
"https://docs.google.com/feeds"};
finalListSCOPES=Arrays.asList(SCOPESArray);
KeyStorekeystore=KeyStore.getInstance("PKCS12");
keystore.load(
getResources().openRawResource(R.raw.piandroidprojects),
"notasecret".toCharArray());
PrivateKeykey=(PrivateKey)keystore.getKey("privatekey",
"notasecret".toCharArray());
GoogleCredentialcredential=
newGoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountPrivateKey(key)
.setServiceAccountId("1490268255705eecriag0m9jbo50ohnt59sest5694d@developer.gserviceaccount.com")
.setServiceAccountScopes(SCOPES)
.build();
service.setOAuth2Credentials(credential);
URLSPREADSHEET_FEED_URL=new
URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full");
SpreadsheetFeedfeed=
service.getFeed(SPREADSHEET_FEED_URL,SpreadsheetFeed.class);
List<SpreadsheetEntry>spreadsheets=feed.getEntries();
returnspreadsheets.get(0).getWorksheets();
}catch(MalformedURLExceptione){
e.printStackTrace();
}catch(ServiceExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(GeneralSecurityExceptione){
e.printStackTrace();
}
returnnull;
}
protectedvoidonPostExecute(finalList<WorksheetEntry>worksheets){
if(worksheets==null||worksheets.size()==0){
Toast.makeText(MapsActivity.this,"Nothingsavedyet",
Toast.LENGTH_LONG).show();
}else{
finalList<String>worksheetTitles=
newArrayList<String>();
for(WorksheetEntryworksheet:worksheets){
worksheetTitles.add(
worksheet.getTitle().getPlainText());
}
AlertDialog.BuilderalertDialogBuilder=
newAlertDialog.Builder(MapsActivity.this);
alertDialogBuilder.setTitle("Selectaworksheet");
alertDialogBuilder.setAdapter(
newArrayAdapter<String>(
MapsActivity.this,
android.R.layout.simple_list_item_1,
worksheetTitles.toArray(newString[0])),
newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
newRetrieveWorksheetContent()
.execute(worksheets.get(which));
}
});
alertDialogBuilder.create().show();
}
}
}
Beforewedescribetheprecedingcode,defineaninstancevariableforthespreadsheet
service,whichisusedinthetaskwehavejustdefined:
SpreadsheetServiceservice;
TheAndroidAsyncTaskrequiresustooverridethedoInBackgroundmethod,whichis
executedinanewthreadwheneverwecalltheexecutemethodofthetaskthatwe
performedinonCreate.IndoInBackground,wewilldefineKeyStore,andloadtheP12
filethatwe’vedownloadedfromtheGoogleDeveloperConsoleandcopiedtotheraw
directoryofourAndroidproject.NotethatnotasecretwasthesecretthattheDeveloper
ConsoleinformedmeaboutwhenIcreatedanddownloadedtheP12file.Also,insidethe
setServiceAccountIdmethod,you’llneedtouseyourownaccountname.Youcanfindit
intheDeveloperConsoleundertheServiceaccountsectionintheEmailaddressfieldas
wellasintheJSONkeyfileclient_emailfield.Inthebackgroundmethod,afterloading
thekeyfileanddefiningthecredentials,we’llauthorizeourselvestoGoogleSpreadsheets
serviceusingOAuth.We’llsimplygetthefirstspreadsheetthatIassumeis
CAR_OBD_SHEETandreturntheworksheetsinit.Wecouldgothroughallthespreadsheets
andsearchforthetitleaswell,butIwillskipthispartofthecodeandassumethatyou
haveonlyonespreadsheetinyouraccountwiththetitleasCAR_OBD_SHEET.
Thesecondfunctionwe’lldefineisonPostExecute.ThisfunctioniscalledinsidetheUI
threadbytheAndroidsystemwheneverbackgroundprocessingisperformed.Itis
importantthatthisisrunintheUIthreadaswecannottouchUIelementsifwerunUIrelatedcodeinnon-UIthreads.
NoteherethatthereturnvalueofthedoInBackgroundmethodissentasaparametertothe
onPostExecutemethod,whichisalistofworksheetsfoundinasheetintheGoogleDocs
service.We’llgothroughthislistandcollectthetitlesinanotherlist.Then,we’llshow
thislistinapop-updialogbox,whichausercanclickonandselect.Whenevertheuser
selectsoneoftheworksheets,AndroidcallstheonClickmethodof
DialogInterface.OnClickListener,whichwehavesentinasaparametertotheadapter
ofAlertDialog.ThismethodcallstheexecutemethodofanotherAsyncTaskthatwe’ll
callRetrieveWorksheetContent,which,asthenameimplies,retrievesthecontentofthe
selectedworksheet.Hereisthedefinitionforthistask:
classRetrieveWorksheetContentextendsAsyncTask<WorksheetEntry,Void,
List<List<Object>>>{
@Override
protectedList<List<Object>>doInBackground(WorksheetEntryparams){
WorksheetEntryworksheetEntry=params[0];
URLlistFeedUrl=worksheetEntry.getListFeedUrl();
List<List<Object>>values=newArrayList<List<Object>>();
try{
ListFeedfeed=
service.getFeed(listFeedUrl,ListFeed.class);
for(ListEntryentry:feed.getEntries()){
List<Object>rowValues=newArrayList<Object>();
for(Stringtag:entry.getCustomElements().getTags()){
Objectvalue=
entry.getCustomElements().getValue(tag);
rowValues.add(value);
}
values.add(rowValues);
}
}catch(IOExceptione){
e.printStackTrace();
}catch(ServiceExceptione){
e.printStackTrace();
}
returnvalues;
}
@Override
protectedvoidonPostExecute(List<List<Object>>values){
setUpMap(values);
super.onPostExecute(values);
}
}
Here,themostimportantpartiswhereweiteratethroughfeed.getEntries(),which
referstoalltherowsinthespreadsheetandthepartwhereweiteratethrough
entry.getCustomElements().getTags(),referstoallthecolumns.Then,in
onPostExecute,we’llcallthesetUpMapmethodwithallthevaluesthatwehaveretrieved.
Insidethismethod,we’llcreatemarkersonthemapthatiscontainedinMapsActivity.
CommentouttheautomaticallydefinedsetUpMapmethodifyoudonotwantamarkerat
location0,0,whichAndroidStudiohasdefinedforyouasanexample:
privatevoidsetUpMap(List<List<Object>>values){
for(List<Object>value:values){
Stringtitle=values.get(0).toString();
try{
doublelatitude=
Double.parseDouble(value.get(1).toString());
doublelongitude=
Double.parseDouble(value.get(2).toString());
if(latitude!=0&&longitude!=0)
mMap.addMarker(
newMarkerOptions().position(
newLatLng(latitude,longitude)))
.setTitle(title);
}catch(NumberFormatExceptionex){
}
}
}
Whenyoustarttheapp,youwillseealistofspreadsheetstochoosefrom:
Thelistofspreadsheets
Next,afterselectingoneofthesesheets,youcanseethedataonthemap:
Thedatapointsonthemap
Summary
Inthischapter,wecoveredalotofcontent,rangingfromcardiagnosticstoAndroid
devicerootprocess.WeevencoveredalotofAndroidcode.
Ihopethatallofyouhavefunimplementingtheseexcitingprojects,willtrytoenhance
themandmakingthembetterthanIdid.
Index
A
AndroidCentral
URL/RootingSamsungGalaxyS2
Androiddevice
using,asaccesspoint/UsingyourAndroiddeviceasanaccesspoint
rooting,alternative/Analternativetorooting
SamsungGalaxyS2,rooting/RootingSamsungGalaxyS2
tethering,enabling/Enablingtetheringonbeingconnectedtoapowersource
automaticrestart,onpowerconnect/Automaticrestartonpowerconnect
autotethering/Autotethering
data,sendingtocloud/Sendingdatatothecloud
Androidphone
rebootcommand,sendingtoPi/Sendingtherebootcommandfromyour
AndroidphonetothePi
morecommands,sendingtoPi/SendingmorecommandsfromyourAndroid
phonetothePi
AndroidStudio
URL/ConnectingfromanAndroidapp
B
BLEScannerapp/Installingthenecessarycomponents,Connectingfroman
Androidapp
BluePixelTechnologiesLLP/Installingthenecessarycomponents
BluetoothLowEnergy(BLE)
necessarycomponents,installing/Installingthenecessarycomponents
versions,URL/Installingthenecessarycomponents
sensorservice,adding/AddingasensorservicetoBluetoothLowEnergy
Androidapp,connectingfrom/ConnectingfromanAndroidapp
rebootcommand,sendingfromAndroidphonetoPi/Sendingthereboot
commandfromyourAndroidphonetothePi
morecommands,sendingfromAndroidphonetoPi/Sendingmorecommands
fromyourAndroidphonetothePi
LEDcommand,lighting/LightingtheLEDs
soundcommand,playing/PlayingsoundsonyourPi
commands,combining/Combiningthecommandsandbeinginformedon
incomingcalls
C
camera
hardwareconfigurations/Hardwareandsoftwareconfigurations
softwareconfigurations/Hardwareandsoftwareconfigurations
cardata
collecting/Collectingthecardata
collecting,fromPi/GettingthecardatatothePi
carlocation
findingout/Findingoutthecarlocation
ConnectBot
about/RemoteconsoletothePifromAndroid
cron/Installingthedatabase
crontab/Installingthedatabase
CWMSuperUserfile/RootingSamsungGalaxyS2
D
data
sending,tocloud/Sendingdatatothecloud
database
andwebserver,implementation/Asimpledatabaseandwebserver
implementation
installing/Installingthedatabase
E
ELM327-Bluetooth/Collectingthecardata
F
files
exchanging,betweenPiandAndroid/ExchangingfilesbetweenthePiand
Android
G
GenericAttributeProfile(Gatt)/Installingthenecessarycomponents
H
HTTPclient
URL/Retrievingmeasurements
J
Javaclient
URL/Retrievingmeasurements
JebooKernel/RootingSamsungGalaxyS2
K
KeyesDHT11(DHT11)/Connectingthesensor
Kodi
starting,onboot/StartingKodionboot
Kore/ConnectingtothemediacenterviaremotecontrolfromAndroid
L
LEDcommand
lighting/LightingtheLEDs
Linux,installationonPi
about/InstallingLinuxonyourPi
NOOBSused/InstallingusingNOOBS
Raspbianimageused/InstallingusingaRaspbianimage
OSimage,extractingtoSDcard/ExtractingtheOSimagetoanSDcard
M
mediacenter
installing/InstallingandsettingupamediacenteronPi
settingup/InstallingandsettingupamediacenteronPi
Kodi,startingonboot/StartingKodionboot
connecting,viaremotecontrolfromAndroid/Connectingtothemediacenter
viaremotecontrolfromAndroid
about/Gettingmorefromyourmediacenter,WatchingvideosusingKodionan
Androiddevice,StreamingtheAndroiddisplaytoKodi
installing,NOOBSused/InstallingthemediacenterusingNOOBS
N
NOOBS
URL/InstallingusingNOOBS,InstallingthemediacenterusingNOOBS
used,forinstallingmediacenter/InstallingthemediacenterusingNOOBS
O
OAuthclient
URL/Retrievingmeasurements
Odin/RootingSamsungGalaxyS2
On-boarddiagnostics(OBD)/Collectingthecardata
P
Pi
prerequisites/Prerequisites
settings,changesmaking/Makingnecessarychangesinsettings
components,installing/InstallingnecessarycomponentsinthePiandAndroid
andAndroid,connecting/ConnectingthePiandAndroid
remoteconsole,fromAndroid/RemoteconsoletothePifromAndroid
andAndroid,filesexchangingbetween/ExchangingfilesbetweenthePiand
Android
mediacenter,settingup/InstallingandsettingupamediacenteronPi
Plugable/Installingthenecessarycomponents
portforwarding/Connectingfromanywhere
pyOBD-pitool/GettingthecardatatothePi
R
RaspberryPiFoundation
URL/Hardwareandsoftwareconfigurations
Raspbian/InstallingLinuxonyourPi
Raspbianimage
URL/InstallingusingaRaspbianimage
RaspiCamRemoteapp
about/StreamingvideotoanAndroiddevice
VLCconfigurations,manual/ManualVLCconfigurations
rebootcommand
sending,fromAndroidphonetoPi/Sendingtherebootcommandfromyour
AndroidphonetothePi
remoteconsole
toPi,fromAndroid/RemoteconsoletothePifromAndroid
rooting
alternatives/Analternativetorooting
S
ScreenStreamMirroring/StreamingtheAndroiddisplaytoKodi
SDAssociation
URL/InstallingLinuxonyourPi
SDFormatter/InstallingLinuxonyourPi
SecureShell(SSH)
about/RemoteconsoletothePifromAndroid
sensor
connecting/Connectingthesensor
sensorservice
adding,toBluetoothLowEnergy(BLE)/AddingasensorservicetoBluetooth
LowEnergy
servers
managing/Simplemanagementofservers
soundcommand
playing/PlayingsoundsonyourPi
surveillanceimages
accessing,onWeb/AccessingsurveillanceimagesontheWeb
surveillancemode
about/Thesurveillancemode
V
video
streaming,toAndroiddevice/StreamingvideotoanAndroiddevice
VLCconfigurations/ManualVLCconfigurations
VLCconfigurations
manual/ManualVLCconfigurations
W
webserver
installing/Installingthewebserver
Wi-Fi
using,onPi/WhatifIwanttouseWi-FionthePi?
Win32DiskImager
URL/ExtractingtheOSimagetoanSDcard