User Tools

Site Tools


growth_chamber

Information for Growth Chamber Data Logger System:

Will be updated to allow Reactive Programming. This will allow the data logger data to be continuously updated within the Shiny app. Once new measurements are recorded and the timestamp changes for the data, the Shiny app will run and update the information displayed. A user input to allow different date ranges will also be included.

The Growth Chamber Data Logger System consists of a Raspberry Pi 3 B+ with a Sense HAT (https://pythonhosted.org/sense-hat/) including these sensors:

  • Gyroscope
  • Accelerometer
  • Magnetometer
  • Temperature
  • Barometric pressure
  • Humidity
 Python code available here: https://github.com/RPi-Distro/python-sense-hat 

To set up the Raspberry Pi with R, instructions were loosely followed from this source: https://community.rstudio.com/t/setting-up-your-own-shiny-server-rstudio-server-on-a-raspberry-pi-3b/18982

Disabling BT/wifi:

#call config.txt file and add these settings at end
sudo nano /boot/config.txt
dtoverlay=pi3-disable-bt
dtoverlay=pi3-disable-wifi

Making swap memory for better installing/compiling with R (this process does appear to warn you/errors but works):

sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=3072
sudo /sbin/mkswap /var/swap.1
sudo /sbin/swapon /var/swap.1
sudo sh -c 'echo "/var/swap.1 swap swap defaults 0 0 " >> /etc/fstab'
sudo nano /etc/sysctl.conf
# Add this at the end
    vm.swappiness=10

Install R (was 3.6.0 at time of writing)

sudo apt-get install -y gfortran libreadline6-dev libx11-dev libxt-dev \
       libpng-dev libjpeg-dev libcairo2-dev xvfb \
       libbz2-dev libzstd-dev liblzma-dev \
       libcurl4-openssl-dev \
       texinfo texlive texlive-fonts-extra \
       screen wget openjdk-8-jdk
cd /usr/local/src
sudo wget https://cran.rstudio.com/src/base/R-3/R-3.6.0.tar.gz
sudo su
tar zxvf R-3.6.0.tar.gz
cd R-3.6.0
./configure --enable-R-shlib #--with-blas --with-lapack #optional
make
make install
cd ..
rm -rf R-3.6.0*
exit
cd

sudo apt-get update sudo apt-get upgrade sudo apt-get install libssl-dev

Install all the packages for shiny and required dependencies. This set is sufficient for the shiny-server, which may be overkill for only deploying a shiny app to the host since these are not hosted on the pi itself.

sudo su - -c "R -e \"install.packages('later', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('fs', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('Rcpp', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('httpuv', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('mime', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('jsonlite', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('digest', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('htmltools', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('xtable', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('R6', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('Cairo', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('sourcetools', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('shiny', repos='http://cran.rstudio.com/')\""
sudo su - -c "R -e \"install.packages('rsconnect', repos='http://cran.rstudio.com/')\""

if (!require(“devtools”))

install.packages("devtools")

devtools::install_github(“rstudio/rsconnect”)

Install cmake

wget https://cmake.org/files/v3.13/cmake-3.13.0.tar.gz # Check for the latest version on https://cmake.org/files/
tar xzf cmake-3.13.0.tar.gz
cd cmake-3.13.0
./configure; make
sudo make install
cd

A strange issue arises with openssl/PKG_CONFIG_PATH to install rsconnect in R. Try

cd ~/lib
wget https://www.openssl.org/source/openssl-1.0.2o.tar.gz
tar -xzvf openssl-1.0.2o.tar.gz
mkdir openssl
cd openssl-1.0.2o
./config -fPIC shared --openssldir=$HOME/lib/openssl 
make -j16
make test -j16
make install
echo 'export PATH=$HOME/lib/openssl/bin:$PATH' >> ~/.bash_profile
echo 'export PKG_CONFIG_PATH="$HOME/lib/openssl/lib/pkgconfig:$PKG_CONFIG_PATH"' >> ~/.bash_profile
echo 'export LD_LIBRARY_PATH="$HOME/lib/openssl/lib:$LD_LIBRARY_PATH"' >> ~/.bash_profile
rm ~/lib/openssl-1.0.2o.tar.gz

Attempting to push the shiny app using R, but if R + RStudio is wanted, this code will do it ~12 hours:

sudo git clone https://github.com/rstudio/rstudio.git
cd rstudio/dependencies/linux
sudo su
./install-dependencies-debian --exclude-qt-sdk
apt-get install -y openjdk-8-jdk
apt autoremove
cd /home/pi/rstudio
mkdir build
cd build
cmake .. -DRSTUDIO_TARGET=Server -DCMAKE_BUILD_TYPE=Debug
make install
 
#Configure Rstudio
cd
useradd -r rstudio-server
cp /usr/local/lib/rstudio-server/extras/init.d/debian/rstudio-server /etc/init.d/rstudio-server
chmod +x /etc/init.d/rstudio-server 
update-rc.d rstudio-server defaults
ln -f -s /usr/local/lib/rstudio-server/bin/rstudio-server /usr/sbin/rstudio-server
chmod 777 -R /usr/local/lib/R/site-library/
mkdir -p /var/run/rstudio-server
mkdir -p /var/lock/rstudio-server
mkdir -p /var/log/rstudio-server
mkdir -p /var/lib/rstudio-server
rm -rf /home/pi/rstudio
sudo nano /etc/init.d/rstudio-server
# Modify your PATH for ussing the compiled version of R
	# PATH=/usr/local/bin/:/sbin:/usr/sbin:/bin:/usr/bin
systemctl daemon-reload
rstudio-server start
exit

The python code outputs a file that is used with R & RStudio to display as a Shiny app within an html iframe.

For displaying on a webpage, a Shiny app written in R is excellent:

Example R .app for deploying data taken from the python output file:

Load the required packages

library(shiny)
library(lubridate)
library(ggplot2)

After setting working directory to contain the .app file(containing the ui.R & server.R), check the data:

  #check the data
gc109 <- read.csv("SenseLog2019test.csv", header = TRUE)
head(gc109)   
 
#checking an example column, such as temperature
temp <- plot(gc109$timestamp,gc109$temp_h)
temp       
 
#ensure it is data.frame                        
gc109df <- as.data.frame(gc109)
head(gc109df)

Next, call aggregate() to take the average of each measurement for each minute. Another option is to only have the Raspberry Pi and python script record measurements every minute/every hour etc. In order to work the timestamp, the lubridate function was used to parse the date and time into a workable form.

intohour <- parse_date_time(gc109df$timestamp, orders ="mdy HMS" )
 
newtime <- format(intohour, format = '%Y%m%d %H:%M')
 
newtime1 <- parse_date_time(newtime, orders ="ymd HM" )
 
gc109df$timestamp <- newtime1
 
test <- aggregate(gc109df, by=list(gc109df$timestamp), mean)(gc109df)

Rename the default columns from the Sense HAT and set the ggplot theme:

colnames(test)[colnames(test)=="timestamp"] <- "Date"
colnames(test)[colnames(test)=="temp_h"] <- "Temperature"
 
theme_set(theme_bw())

Next in the Shiny app.R, set up the ui. This also contains a javascript for fixing iframes for use with dokuwiki: Information for creating a “responsive” iframe: https://dlukes.github.io/responsive-iframe.html

# Define UI for application that draws a histogram
ui <- fluidPage(
 
# Application title
titlePanel("Growth Chamber Room 109"),
# Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
 
                        max = 50,
                        value = 30)
        ),
 
        # Show a plot of the generated distribution
        mainPanel(
                plotOutput("distPlot"),
                  tags$head(
                        tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                        type="text/javascript")
        ),
        HTML('<div data-iframe-height></div>'),
 
        plotOutput("humiPlot"),
        tags$head(
            tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                        type="text/javascript")
        ),
        HTML('<div data-iframe-height></div>'),
 
        plotOutput("presPlot"),
        tags$head(
            tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                        type="text/javascript")
        ),
        HTML('<div data-iframe-height></div>')
        )
    )
)

Next, write the server logic for outputting the plots:

server <- function(input, output) {
 
    output$distPlot <- renderPlot({
 
         ggplot(aes(x=Date, y = Temperature), data = test) + geom_point()
 
 
    })
 
    output$humiPlot <- renderPlot({
 
        ggplot(aes(x=Date, y = humidity), data = test) + geom_point()
    })
 
    output$presPlot <- renderPlot({
 
        ggplot(aes(x=Date, y = pressure), data = test) + geom_point()
    })
}
 
# Run the application 
shinyApp(ui = ui, server = server)

Once you have finished and setup a free Shiny app from https://www.shinyapps.io/, you can deploy the app online in RStudio:

library(rsconnect)
deployApp(GrowthChamber)

For embedding in a webpage such as this (using dokuwiki/html/script), include this code within the dokuwiki page. Update the src=“YOUR_SHINY_APP_ADDRESS_HERE” and the shiny app should be looking sleek.

<html>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.min.js"></script>
<style>
  iframe {
    min-width: 100%;
  }
</style>
<iframe id="myIframe" src="YOUR_SHINY_APP_ADDRESS_HERE/" scrolling="no" frameborder="no"></iframe>
<script>
  iFrameResize({
    heightCalculationMethod: 'taggedElement'
  });
</script>
</html>

Check it out:

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#
 
library(shiny)
library(tools)
library(lubridate)
library(ggplot2)
library(dplyr)
theme_set(theme_bw())
 
ui <- fluidPage(
    titlePanel("Growth Chamber 109"),
 
 
    column(4, wellPanel(
        dateRangeInput(
            'dateRange',
            label = 'Filter results by date',
            start = as.Date('2019-05-10') ,
            end = NULL
        )
    )),
 
 
    plotOutput("Temperature"),
    tags$head(
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                    type = "text/javascript")
    ),
    HTML('<div data-iframe-height></div>'),
 
    plotOutput("Humidity"),
    tags$head(
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                    type = "text/javascript")
    ),
    HTML('<div data-iframe-height></div>'),
 
    plotOutput("Pressure"),
    tags$head(
        tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                    type = "text/javascript")
    ),
    HTML('<div data-iframe-height></div>')
 
 
 
 
 
)
 
 
#The reactive file reader reads in the Raspberry Pi Python generated file SenseLog.csv and returns as data()
server <- function(input, output, session) {
    data <- reactiveFileReader(
        intervalMillis = 90000,
        session = session,
        filePath = "SenseLog.csv",
        readFunc = read.csv)
 
 
    #Server call for rendering the temperature plot
    output$Temperature <- renderPlot({
 
 
        #Change the function output data() to gc109. Reactive expressions/functions and the () mess me up sometimes
        gc109 <- data()
 
 
 
        #Parse time out  in proper format
        gc109$timestamp <- strptime(gc109$timestamp, "%Y-%m-%d %H:%M")
 
 
        #Filter data from logger based on date range input from session
        try1 <- subset(gc109, timestamp >= input$dateRange[1])
        try2 <- subset(try1, timestamp <= input$dateRange[2])
 
 
        #Fix column header names
        colnames(try2)[colnames(try1) == "timestamp"] <- "Date"
        colnames(try2)[colnames(try1) == "temp_h"] <- "Temperature"
        colnames(try2)[colnames(try1) == "humidity"] <- "Humidity"
        colnames(try2)[colnames(try1) == "pressure"] <- "Pressure"
 
 
        #Fix dates/maintain time to plot properly
        try2$Date <- as.POSIXct(try2$Date)
 
 
        #Generate temperature plot
 
        ggplot(aes(x = Date, y = Temperature), data = try2) + geom_point() +
            theme(text = element_text(size = 20))
 
    })
 
 
 
    data <- reactiveFileReader(
        intervalMillis = 5000,
        session = session,
        filePath = "SenseLog.csv",
        readFunc = read.csv)
 
 
    #Server call for rendering the humidity plot
    output$Humidity <- renderPlot({
 
 
        #Change the function output data() to gc109. Reactive expressions/functions and the () mess me up sometimes
        gc109 <- data()
 
 
 
        #Parse time out  in proper format
        gc109$timestamp <- strptime(gc109$timestamp, "%Y-%m-%d %H:%M")
 
 
        #Filter data from logger based on date range input from session
        try1 <- subset(gc109, timestamp >= input$dateRange[1])
        try2 <- subset(try1, timestamp <= input$dateRange[2])
 
 
        #Fix column header names
        colnames(try2)[colnames(try1) == "timestamp"] <- "Date"
        colnames(try2)[colnames(try1) == "temp_h"] <- "Temperature"
        colnames(try2)[colnames(try1) == "humidity"] <- "Humidity"
        colnames(try2)[colnames(try1) == "pressure"] <- "Pressure"
 
 
        #Fix dates/maintain time to plot properly
        try2$Date <- as.POSIXct(try2$Date)
 
 
        #Generate temperature plot
 
        ggplot(aes(x = Date, y = Humidity), data = try2) + geom_point() +
            theme(text = element_text(size = 20))
 
    })
 
    data <- reactiveFileReader(
        intervalMillis = 5000,
        session = session,
        filePath = "SenseLog.csv",
        readFunc = read.csv)
 
 
    #Server call for rendering the pressure plot
    output$Pressure <- renderPlot({
 
 
        #Change the function output data() to gc109. Reactive expressions/functions and the () mess me up sometimes
        gc109 <- data()
 
 
 
        #Parse time out  in proper format
        gc109$timestamp <- strptime(gc109$timestamp, "%Y-%m-%d %H:%M")
 
 
        #Filter data from logger based on date range input from session
        try1 <- subset(gc109, timestamp >= input$dateRange[1])
        try2 <- subset(try1, timestamp <= input$dateRange[2])
 
 
        #Fix column header names
        colnames(try2)[colnames(try1) == "timestamp"] <- "Date"
        colnames(try2)[colnames(try1) == "temp_h"] <- "Temperature"
        colnames(try2)[colnames(try1) == "humidity"] <- "Humidity"
        colnames(try2)[colnames(try1) == "pressure"] <- "Pressure"
 
 
        #Fix dates/maintain time to plot properly
        try2$Date <- as.POSIXct(try2$Date)
 
 
        #Generate temperature plot
 
        ggplot(aes(x = Date, y = Pressure), data = try2) + geom_point() +
            theme(text = element_text(size = 20))
 
    })
 
}
 
shinyApp(ui, server)
growth_chamber.txt · Last modified: 2019/05/17 22:15 by sxd