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