Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

smarttools

Helper functions for downloading and processing precision dairy monitoring data — feed/water intake, weather, and heat stress:

  • download_data() — authenticates with the C-Lock Inc. portal API and downloads weight (SmartScale) or intake (SmartFeed) data, as daily summaries or individual visits.
  • download_weather() — pulls daily weather data (temperature, humidity, wind, solar radiation, precipitation, soil moisture/temperature, elevation) for a given latitude/longitude from NASA POWER, and computes the Temperature-Humidity Index (THI, NRC 1971).
  • summarise_intakes() — aggregates intake visits to one row per animal per day: visit count, total/mean/min/max intake, and the behavioral traits from Dressler et al. (2023) (time per session, session interval, intake rate), joined with matching daily T2M/THI from download_weather(). Also separates out negative-intake visits for review.
  • summarise_bw() — aggregates weight visits to one row per animal per day, applying the company's front-feet-to-full-body correction factor (1.76) and flagging implausible visit weights as outliers for review.
  • process_VRfiles() / mixers() — re-exported from feedeffir; process feed bin data from the Hokofarm Group Insentec (RIC) system. process_VRfiles() processes a single day's VR######.DAT file; mixers() batch-processes a folder of them against a treatment-group roster for daily/weekly/trial diet-mixing summaries. See ?feedeffir::process_VRfiles / ?feedeffir::mixers for full parameter documentation.

Installation

# install.packages("remotes")
remotes::install_github("GMBog/smarttools")

This also installs feedeffir (declared as a Remotes: dependency) for process_VRfiles()/mixers().

Usage

C-Lock portal data

Requires a C-Lock portal account. Set credentials as environment variables (e.g. in ~/.Renviron) so they never need to be hardcoded in scripts:

CLOCK_USER=your_portal_username
CLOCK_PASS=your_portal_password
library(smarttools)

unit <- "11228,11229,11230,11231,11232,11233"
start_date <- "2026-07-13"
end_date <- as.character(Sys.Date())

# Individual visits
visits_df <- download_data(t = "weight", d = "visits", unit = unit,
                            start_date = start_date, end_date = end_date)

# Daily summaries
daily_df <- download_data(t = "weight", d = "daily", unit = unit,
                           start_date = start_date, end_date = end_date)

intake_visits_df <- download_data(t = "intake", d = "visits", unit = unit,
                                   start_date = start_date, end_date = end_date)

intake_daily_df <- download_data(t = "intake", d = "daily", unit = unit,
                                  start_date = start_date, end_date = end_date)

NASA POWER weather + THI

No authentication required.

library(smarttools)

weather_df <- download_weather(
  lat = 38.53706526753634,
  lon = -121.75995771946077,
  start_date = "2026-07-21",
  end_date = as.character(Sys.Date())
)

Returns one row per day with the requested weather parameters, site elevation, and THI/THI_max computed automatically when temperature and humidity are among the requested parameters. Default parameters:

Code Description
T2M / T2M_MAX / T2M_MIN Air temperature at 2m (mean/max/min, °C)
RH2M Relative humidity at 2m (%)
WS2M Wind speed at 2m (m/s)
ALLSKY_SFC_SW_DWN Surface solar radiation (MJ/m²/day)
PRECTOTCORR Precipitation (mm/day)
GWETTOP / GWETROOT Soil wetness, surface / root zone (fraction)
TS Earth skin (soil surface) temperature (°C)

Daily water intake summary + weather

library(smarttools)

vdf_WI <- download_data(
  t = "intake", d = "visits",
  unit = "11228,11229,11230,11231,11232,11233",
  start_date = "2026-07-21",
  end_date = as.character(Sys.Date())
)

result <- summarise_intakes(
  vdf_WI,
  lat = 38.53706526753634,
  lon = -121.75995771946077
)
daily_WI <- result$daily
negative_intakes <- result$negative_intakes

Drops visits with a blank RFID, and visits that aren't a valid session per Dressler et al. (2023) (Duration > 5s and < 3600s). Visits with a negative IntakeKG are excluded from the daily summary and returned separately in negative_intakes for review. daily has one row per RFID/Date:

Column Description
T2M / THI From download_weather() for that date; omitted if the weather download fails
DailySession Number of valid visits
DailyWaterIntakeKG Total daily intake
SessionSizeKG / MinSessionSizeKG / MaxSessionSizeKG Mean/min/max intake per visit
TimePerSessionSec Mean visit duration
SessionIntervalMin Mean time between consecutive same-day visits (NA if only one visit that day)
IntakeRateGperSec Each visit's own rate (IntakeKG*1000/Duration), averaged across the day

Daily body weight summary

library(smarttools)

vdf_BW <- download_data(
  t = "weight", d = "visits",
  unit = "11228,11229,11230,11231,11232,11233",
  start_date = "2026-07-21",
  end_date = as.character(Sys.Date())
)

result <- summarise_bw(vdf_BW)
daily_bw <- result$daily
outliers <- result$outliers

Drops visits with a blank RFID. Each WeightKG reading only captures the animal's front two feet on the scale, so BW_kg is the mean of that day's visit weights (RawWeightKG) multiplied by 1.76 to estimate full body weight. Visits with an implausible WeightKG are flagged as outliers using Tukey's boxplot rule, with quartiles computed per RFID across its full set of visits in df (not per day, since a single day often has too few visits to estimate quartiles reliably); flagged visits are excluded from daily and returned separately in outliers for review. daily has one row per RFID/Date: n, RawWeightKG, BW_kg, and SDBW_kg (standard deviation, same 1.76 scaling as BW_kg; NA if only one visit that day).

Hokofarm Group Insentec (RIC) feed bin files

library(smarttools)

# Single day's VR file
intakes <- process_VRfiles(
  exp = "TRIAL01",
  VRfile = "path/to/VR260721.DAT",
  bins = seq(1, 32),
  save_dir = "output/"
)

# Batch-process a folder of VR files against a treatment-group roster
result <- mixers(
  start_date = "2026-07-13",
  VRfolder = "path/to/vr_files/",
  groups = "path/to/groups.csv",
  bins = seq(1, 32)
)

More examples are in examples/.

License

MIT

About

Tools for Downloading and Processing SmartFeed/SmartScale Data

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages