Introduction

PeachCloud is a low-power, lightweight hardware device designed to facilitate peer-to-peer communication across social networks. We aim to return (cloud) computing back into our homes and local communities in a way which fosters increased trust in one another and the socio-technical systems we inhabit.

This guide is intended to comprehensively document the PeachCloud project. It includes information about the hardware and software which comprises the device, as well as insight into the goals and design principles the project has grown from.

PeachCloud physical interface with PeachCloud logo shown on an OLED display

Story

Below are excerpts from Scuttlebutt private messages exchanged between @dinosaur (Michael Williams) and @glyph (Andrew Reid) at the start of their collaboration in early-2018. These conversations helped tell the story of what PeachCloud was to become:

@dinosaur

for me, i know at least one story in my mind, which relates to the story i told you about solarpunk trailer parks.

in the book Walkaway, i was struck by how computers were portrayed. every home had a computer system to help automate the household. and not just physical automation as we know it today (automated cooking, automation fabrication, etc), but so much was social automation, group resource coordination, task planning and management. that’s what i find most exciting.

so for me, PeachCloud is part of a larger story about every household having a home computer, which helps them connect with others, which helps them communicate with others, which helps them coordinate shared resources with others, which helps them get shit done with others.

then, if every home (and the corresponding infrastructure) itself is modular, portable, reproducible, and enjoyable, then our home computers can support us in this ever-evolving lifestyle. i find this future very exciting!

@glyph

I love the vision you put forward of the houeshold as facilitator of connecting, communicating, coordinating and acting.

Perhaps it’ll come as no surprise, but I couldn’t help thinking of mycelium while reading your messages. I think this connects beautifully with what you shared about your Spirit-Being / Creature being a Tree: nurturing, calm, stable, sensorially-opened and receptive, deeply-rooted, seasonally-responsive. This also seems like a great metaphor for the household. Who wouldn’t want to dwell in a tree?! So then, perhaps PeachCloud could be envisioned as part of the rhizosphere of the household; the digital access-point to the Reciprocity Transport Layer (RTL) [fundamentally about sharing with one another and growing together].

Here’s a little sketch I did this morning, inspired by your thoughts (there are some mixed metaphors / concerns in there but I think it’ll make sense to you). I took a high-level pass at thinking about measures of project success…will think-feel into this more deeply as we go. I also used the tree metaphor as a way to think about the layering of the interface:

Notes and sketches in a ruled notebook

Design Principles

The following design principles were created through collaborative story-telling and visioning at the start of the PeachCloud project. While not strictly technical in nature, this information is shared here to give future contributors and peers a feel for the guiding spirit behind this work. Implementation details should always be made in service of this underlying vision.

  • Better communication infrastructure for local communities
    • Able to store the long-tail data (the niche content that isn’t mass popular but nevertheless important to support libraries of local culture and knowledge)
    • Able to support real-time media-rich interactions
      • Not just text, but also voice and video mail!
    • Able to transport your data with you as you move locations
    • Create local network topologies and local data centers to match our local social topologies
      • Less dependence on external networks, external data centers, etc
  • Accessible to users
    • Easy to get started for you and your community
    • Easy for non-technical people to use
      • The system is a teacher to guide you on your journey
      • Invite less technical people to become more technical
      • Simple on the surface, powerful under the hood
        • Example: more like Excel spreadsheets, less like Apple interfaces
    • The interface should embody the underlying system
      • Let all the internals leak out for you to see
        • A living system of activity playing on the physical lights
        • Allow users to look at the firehouse of logs, usage, metrics, etc
      • Easy to grok what is happening
        • Physical lights should give you the status at a glance
      • Friendly automation
        • Your personal robot friend, your home computer
        • No surprises, any automation should be upfront and clear
        • Be helpful, but don’t try to guess what the user wants
        • Give the user the power tools to automate their own desires
  • Accessible to contributors
    • Modules are well-documented
    • Code follows best practices
    • Focus on being accessible and maintainable, not being clever and complicated
    • Focus on being boring and just working, not being shiny and perfect
    • Provide an opinionated foundation to build flexible ecosystem
      • Frame is restrictive and has constraints, enables scope and freedom to play inside
      • “Bondage sets you free”
    • Contributions are more than tech
      • Living cultural documentation
      • Peer production as a deployment strategy

Features

PeachCloud features can be broadly divided between device management and Scuttlebutt functionality.

The anticipated features for the MVP release of PeachCloud are listed below. The majority of these features will be exposed via the web interface and some will also be exposed via the physical interface.

Since PeachCloud is built on a JSON-RPC microservices architecture, the APIs of the underlying system should be relatively simple for developers to interface with and extend. Please visit the documentation for individual microservices for further information.

Note: This is a work-in-progress. Expect changes.

Device Features

  • Device status
    • Hardware
      • CPU usage
      • Memory usage
      • Storage usage
      • Disk I/O
    • Software
      • Version info of PeachCloud, sbot, plugins
      • Scripts
      • Plugins
    • Network
      • Display network mode (AP or client)
        • If AP, list connected devices
      • Display current connection(s)
        • Ethernet
        • WiFi
      • Display signal strength
      • Display bandwidth usage
      • Display hostname & external IP
      • Display internal IP
    • Logs
      • Display system logs
    • Errors
      • List errors
      • Report a bug / error
        • Via SSB message
        • Via email
  • Configuration
    • Access control
      • Change user password
      • Change administrator password
    • Network
      • Set network mode (AP or client)
      • List available networks
      • Connect to a network
      • Disconnect from a network
      • Forget a network
      • Modify a network password
    • Updates
      • Check for available updates
      • Download updates
      • Install / apply update
    • Backups
      • Create backup
        • Secret key
        • Configuration (device settings)
      • Export backup
        • External storage (USB)
      • List backup history
      • Schedule backups
      • Delete previous backups / backup history
    • Alerts
      • Set alerts based on:
        • CPU
        • Memory
        • Disk
        • Bandwith-usage
      • List previously-defined alerts
      • Reset alerts
    • Miscellaneous
      • List current datetime
      • Set datetime
      • Display current timezone
      • Set timezone
  • Documentation
    • Browse
      • Scuttlebot
      • Scuttlebutt
      • PeachCloud
    • Search

Scuttlebutt Features

  • Profile
    • Display avatar
    • Set avatar (upload file)
    • Display bio
    • Update bio
  • Peers
    • List friends
    • List followers
    • List follows
    • List locally-connected peers
    • Follow
    • Unfollow
    • Block
    • Mute (private block)
  • Invites
    • Create an invite
      • Text-based (hash)
    • Share an invite
      • Send to a peer within SSB (private message)
      • Share publically within SSB (public post)
      • Send via email
    • Accept an invite
    • Monitor an invite
      • Check if the invite has been accepted
      • For multi-use invites, show number of used & unused invite-slots
    • Cancel an invite (not sure if this is currently possible)
  • Blobs
    • Display size of blob store (disk utilisation)
    • Prune blobs
      • By size
      • By date
      • By author

Quick Deployment

GitHub logo

The instructions, configuration files and scripts referred to in this section can all be found in the peach-config repo.

Prerequisite Steps

Download the latest Debian Buster preview image for RPi3 and flash it to an SD card.

Note: Be sure to use the correct device location in the dd command, otherwise you risk wiping another connected USB device. sudo dmesg | tail can be run after plugging in the SD card to determine the correct device location:

wget https://raspi.debian.net/verified/20200831_raspi_3.img.xz
xzcat 20190628_raspberry-pi-3_buster_PREVIEW.img.xz | sudo dd of=/dev/mmcblk0 bs=64k oflag=dsync status=progress

On Mac OS, use the following command to flash the SD card:

xzcat 20190628_raspberry-pi-3_buster_PREVIEW.img.xz | sudo dd of=/dev/sdcarddisc

Alternatively, use Etcher.

Note: if the above image link stops working, you can find the complete list of Raspberry Pi Debian images here.

Setup

Quick setup commands to connect to a local WiFi network over the wlan0 interface (assuming eth0 connection is not possible):

# username
root
# password (by default raspberry debian requires no password, so we set the password for root here)
passwd
# set interface up (run command twice if you receive 'link is not ready' error on first try)
ip link set wlan0 up
# append ssid and password for wifi access point
wpa_passphrase <SSID> <PASS> > /etc/wpa_supplicant/wpa_supplicant.conf
# open wpa_supplicant.conf
nano /etc/wpa_supplicant/wpa_supplicant.conf

[ Add the following two lines to top of file ]

ctrl_interface=/run/wpa_supplicant
update_config=1

[ Save and exit ]

# open network interfaces config
nano /etc/network/interfaces

[ Add the following lines to the file ]

auto lo
iface lo inet loopback

allow-hotplug wlan0
auto wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

[ Save and exit ]

reboot now

[ Pi should now be connected to the WiFi network ]

Scripts

The setup_dev_env.py script can be executed once your Pi is internet-connected and git and python have been installed. It takes a <USER> argument to create a new system user. You will be prompted to enter a password for your newly created user. The script will install system requirements and copy configuration files relating to networking, I2C and RTC.

TODO: Add flags to (de)select I2C, RTC and Rust install & config. Flags should also be added which allow the installer to choose between development environment and release environment configuration.

apt update
apt install git python
git clone https://github.com/peachcloud/peach-config.git
cd peach-config
python scripts/setup_dev_env.py <USER>

Hardware

PeachCloud is intended to be a low-cost device with a small footprint and relatively low power consumption. It should be easy to modify and extend through the inclusion of additional peripherals and hardware modules, either for future release by the PeachCloud team or by third-parties with basic technical competence.

Single-board Computer (SBC)

The Raspberry Pi 3B+ has been chosen as the development platform for PeachCloud. The 3B+ offers extensive documentation, a 64-bit processor, integrated wireless LAN, Bluetooth and BLE, as well as a 40-pin GPIO header. All of these features make it a powerful and flexible platform for system development.

It is important to note that a range of single-board computers (SBC) can be substituted in place of the 3B+, though some changes in system configuration may be required.

Real-time Clock (RTC)

A real-time clock (RTC) module is included in the PeachCloud device as a means of keeping accurate system time, regardless of any power supply interruptions which may occur during deployment. The RTC module consists of an integrated circuit (IC) for time-keeping and a battery. Having a consistently-accurate system time will make it easier to schedule updates and prevent the end-user from having to update the time themselves.

Physical Interface

PeachCloud includes a 128x64 pixel OLED display and several push-buttons. Together, these components form a physical interface which exposes a simple menu system for displaying system state and allowing basic device interactions. The physical interface is intended to be useful in contexts when browser-based interactions are not possible or desirable.

Requirements

Development is currently taking place with the following hardware:

  • Raspberry Pi 3B+
  • Adafruit 128x64 1.3" OLED Bonnet (product page)
  • DS1338 Real-Time Clock (RTC) module (datasheet)

A breadboard and male-to-female jumper wires are also recommended for prototyping.

If the exact parts specified above are not available, substitutes can be used - provided they conform the following specifications:

  • OLED display
    • 128 x 64 pixels
    • SSD1306-compatible
  • Buttons
    • 7 x push-buttons or 2 x push-buttons and 1 x 5-direction joystick
  • Real-Time Clock (RTC)
    • DS1338 or DS1307

Note: the hardware peripherals listed on this page do not work out-of-the-box with Debian Buster ARM64. You will need to patch the device tree and run additional configuration steps (patches are applied automatically if following the 'quick deployment' method using install scripts). See Configuration in the Operating System section of this document for further information.

GPIO Pinout

The OLED bonnet (with buttons) and DS1338 RTC module are connected to the Pi via GPIO pins.

BCM Pin #FunctionPhysical Pin #Used By
3v3 Power1OLED Bonnet & RTC
BCM 2SDA3OLED Bonnet & RTC
BCM 3SCL5OLED Bonnet & RTC
Ground6OLED Bonnet & RTC
BCM 4Joystick Center7OLED Bonnet
BCM 17Joystick Up11OLED Bonnet
BCM 27Joystick Left13OLED Bonnet
BCM 22Joystick Down15OLED Bonnet
BCM 23Joystick Right16OLED Bonnet
BCM 5Button A29OLED Bonnet
BCM 6Button B31OLED Bonnet

Physical Interface

The PeachCloud physical interface consists of a 5-way joystick, two push-buttons and a 128x64 OLED display.

Development is taking place on the AdaFruit 128x64 1.3" OLED Bonnet. This bonnet comes in the pHAT form-factor and requires 3.3V power. It uses 9 GPIO pins and communicates over I2C. The included OLED display utilises the SSD1306 driver.

Note: the 5-way joystick may be replaced by four or five push-buttons in the release version of the physical interface.

Control

The OLED display shows the PeachCloud logo on start-up. Pressing the A button (#5) loads the root of the menu system. The UP and DOWN directions on the joystick allow scrolling through the menu options, while the A button functions as Select and the B button (#6) functions as Back.

Any button or joystick direction can be pressed to wake the display after selecting Display Off.

Menu Structure

.
├── Networking
│   └── MODE
│   └── STATUS
│   └── NETWORK
│   └── IP
│   └── SIGNAL
│   └── Configuration
│       └── Client Mode
│       └── Access Point Mode
├── System Stats
│   └── CPU
│   └── MEM
│   └── LOAD
│   └── UPTIME
│   └── DATA RX
│   └── DATA TX
├── Display Off
├── Reboot
└── Shutdown

Configuration

This page contains the detailed, step-by-step software configuration instructions required to ensure that all the hardware works correctly. Skip to the quick deployment section for the scripted deployment instructions.

GPIO

GPIO (General Purpose Input Output) appears to be working out-of-the-box, but be aware that all pin numbers are offset by 458 for Debian on the Raspberry Pi 3 (as mentioned in the Debian RaspberryPi3 wiki).

RTC over I²C

Additional configuration is required for Debian Buster ARM64 before I²C devices can function correctly. The following steps are required for the DS1338 module / DS1307 chip:

Tested with DS1338 RTC module.

Ensure i2c-tools and python-smbus Debian packages have been installed. Then run the following to ensure the RTC is correctly wired and connected to the Pi:

sudo modprobe i2c-dev
sudo i2cdetect -y 1

The final command in the sequence prints an array to the console, with 68 denoting the presence of the RTC module. This is a sign that the device is properly wired and connected.

Append the following two lines to /boot/firmware/config.txt:

dtoverlay=i2c-rtc,ds1307
dtparam=i2c_arm=on

Append the following line to /etc/modules:

i2c-dev

Patch the device tree in order to set the clock frequency for I²C devices:

Note: the steps below can be shortened by downloading the pre-patched dtb file from the peach-config repo and using it to replace the dtb file on the Pi's SD card.

Copy the existing dtb (device tree blob) from the Pi microSD card to a more powerful computer running Linux (exact location is up to you). You will find the dtb in the following location:

/boot/firmware/bcm2710-rpi-3-b.dtb

Note: the file may be named bcm2837-rpi-3-b.dtb. In that case, replace all instances of bcm2710 in these instructions with bcm2837.

Once it has been copied to your Linux computer, run the following commands (on the Linux machine):

Install the compiler / decompiler:

sudo apt-get install device-tree-compiler

Change into the direction where you copied the dtb from the Pi:

cd /place/where/dtb/file/was/pasted

Generate a human-readable decompiled device tree (dts):

dtc -I dtb -O dts > bcm2710-rpi-3-b.dts

Open the dts in a text editor and add the clock-frequency property (line 570):

clock-frequency = <0x186a0>;

Save and exit the document. Recompile the patched dts to binary blob format:

dtc -O dtb -o bcm2710-rpi-3-b.dtb bcm2710-rpi-3-b.dts

Copy the resulting dtb onto the Pi microSD card and overwrite the old dtb file (you may wish to backup the old dtb first):

cp bcm2710-rpi-3-b.dtb /boot/firmware/bcm2710-rpi-3-b.dtb

Finally, run the following commands to complete the process:

sudo modprobe i2c-bcm2835
su
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
exit
sudo modprobe rtc-ds1307

Run the i2cdetect tool to ensure the RTC kernel driver is working:

sudo i2cdetect -y 1

A UU entry in the output arrays denotes success. If you still see 68 or similar, the module is not being controlled by the kernel driver.

Ensure no i2c could not read clock-frequency property errors persist in the kernel logs (/var/log/kern.log).

Note: This Scuttlebutt dev-diary post by @glyph documents the process step-by-step (%aEVy1gyTSl4qrbazrwrgnrLs4pRVobELwQjH/TUtsAc=.sha256).

OLED Bonnet

A device tree overlay is required to activate the internal pull-up resistors on the Pi. Without this overlay, some of the buttons on the OLED bonnet will not work.

Begin by downloading the device tree overlay file: mygpio.dtbo.

wget https://github.com/peachcloud/peach-config/raw/main/conf/mygpio.dtbo

Create an overlays directory on the Pi filesystem:

sudo mkdir /boot/firmware/overlays

Copy the overlay file into the overlays directory:

sudo cp mygpio.dtbo /boot/firmware/overlays/

Append the following line to /boot/firmware/config.txt:

device_tree_overlay=overlays/mygpio.dtbo

Reboot to apply the changes. All buttons on the OLED bonnet should now function correctly.

Software

Operating System

Images

PeachCloud runs an unofficial preview image of Debian 10 (Buster). Kernel version: 4.19.0-5-arm64.

Tested images are now available via the Raspberry Pi Debian images page on the Debian wiki. According to Gunnar Wolf, project maintainer and Debian developer, the page: "should serve as a go-grab-it destination for regularly autobuilt images for the Raspberry Pi family". Note that these images are considered unofficial, ie. they are not part of an official Debian project.

Why Debian?

In order to be flexible in supporting single-board computers beyond the Raspberry Pi alone, and to take full advantage of 64-bit support on ARMv8 devices, development for PeachCloud is being targeted at Debian ARM64.

Debian was chosen over the Raspbian operating system for several reasons:

  • Full ARM64 support, unlike Raspbian which uses 32 bit mode
  • Flexibile deployment to a range of single board computers
  • Access to latest code in Debian testing
  • Relatively lightweight base install ( < 2GB )

The downsides to this approach are a lack of support (most online resources assume use of Raspbian) and a minimal set of drivers on the base install.

Networking

PeachCloud has three primary network interfaces: eth0, wlan0 and ap0 (virtual interface). The device supports two wireless modes: client and access point (AP).

In client mode, the wlan0 interface is managed by wpa_supplicant. This allows the PeachCloud device to connect to a WiFi access point in the vicinity. The IP address of the wlan0 interface is dynamically-assigned by the WiFi router it is associated with. While the device is running in this mode, the ap0 interface is set DOWN and the dnsmasq and hostapd processes are stopped.

In access point mode, the ap0 interface is managed by hostapd - with DNS and DHCP leasing being handled by dnsmasq. The IP address of the ap0 interface is set to 11.11.11.10 by default. Connected devices are leased IP addresses in the range of 11.11.11.11 - 11.11.11.30 (for now). While the device is running in this mode, the wlan0 interface is set DOWN and the wpa_supplicant process is stopped.

The peach-network microservice exposes activate_ap() and activate_client() RPC calls for simple switching of the networking mode. This functionality is also exposed by the menu system of the physical interface.

Nginx Configuration

Nginx is used as a reverse proxy for the peach-web application. Requests to http://peach and http://www.peach on port 80 are passed to the peach-web application on http://127.0.0.1:3000.

The configuration file for nginx can be found at /etc/nginx/sites-available/peach.conf. The contents are as follows:

server {
        listen 80;
        server_name peach www.peach;
        location / {
                proxy_pass http://127.0.0.1:3000;
        }
}

Nginx Cheatsheet

Symlink sites-available/*.conf to sites-enabled/*.conf:

sudo ln -s /etc/nginx/sites-available/peach.conf /etc/nginx/sites-enabled/

Check correctness of configuration:

sudo nginx -t

Reload nginx:

sudo nginx -s reload

Microservices

PeachCloud is built primarily with a microservices architecture. Each microservice utilises JSON-RPC - a stateless, light-weight remote procedure call protocol - as a means of exposing functionality and allowing interoperability. This approach produces a collection of services which are highly maintainable and testable, loosely coupled and independently deployable. HTTP and WebSockets are used as transports for the microservices.

The suite of PeachCloud microservices currently includes:

  • peach-buttons (repo)
    • poll GPIO pins for button presses and emit events via pub-sub
  • peach-menu (repo)
    • monitor and interact with the device via the physical interface
  • peach-monitor (repo)
    • monitor network data usage and set alert flags
  • peach-network (repo)
    • query and configure network interfaces
  • peach-oled (repo)
    • write and draw to the OLED display
  • peach-stats (repo)
    • query system statistics

peach-buttons

GitHub logo Build Status Version badge

GPIO microservice module for handling button presses. peach-buttons implements a JSON-RPC server with Publish-Subscribe extension. Each button press results in a JSON-RPC request being sent over websockets to any subscribers. A button code for the pressed button is sent with the request to subscribers, allowing state-specific actions to be taken by the subscriber.

In the case of PeachCloud, the peach-menu microservice subscribes to peach-buttons in order to update the state of the menu after each button press.

Note: This module is relatively stable but is still a work-in-progress.

Directory Tree

.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│   ├── error.rs        // custom ButtonError type and From implementation
│   ├── interrupt.rs    // interrupt handler with GPIO polling
│   ├── lib.rs          // RPC server and pubsub handler, pin definitions
│   └── main.rs         // init logger, call run() & catch application errors

Pin to Button to Button Code Mappings

4 => Center => 0,
27 => Left => 1,
23 => Right => 2,
17 => Up => 3,
22 => Down => 4,
5 => A => 5,
6 => B => 6

Note: peach-buttons utilizes the GPIO character device ABI. This API, stabilized with Linux v4.4, deprecates the legacy sysfs interface to GPIOs that is planned to be removed from the upstream kernel after year 2020.

Setup

Clone this repo:

git clone https://github.com/peachcloud/peach-buttons.git

Move into the repo and compile:

cd peach-buttons
cargo build --release

Run the binary with sudo:

sudo ./target/release/peach-buttons

Logging is made availabe with env_logger:

sudo RUST_LOG=info ./target/release/peach-buttons

Other logging levels include debug, warn and error.

Testing Subscription

Request:

{"id":1,"jsonrpc":"2.0","method":"subscribe_buttons"}

Response:

{"jsonrpc":"2.0","result":1,"id":1}

Event:

{"jsonrpc":"2.0","method":"button_press","params":[0]}

Licensing

AGPL-3.0

peach-menu

GitHub logo Build Status Version badge

OLED menu microservice module for PeachCloud. A state machine which listens for GPIO events (button presses) by subscribing to peach-buttons over websockets and makes JSON-RPC calls to relevant PeachCloud microservices (peach-network, peach-oled, peach-stats).

Note: This module is a work-in-progress.

Directory Tree

.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│   ├── buttons.rs          // JSON-RPC WebSocket client for peach-buttons
│   ├── error.rs            // custom MenuError type & From implementations
│   ├── lib.rs              // launch state machine & RPC client for buttons
│   ├── main.rs             // init logger, call run() & catch application errors
│   ├── network.rs          // JSON-RPC HTTP client for peach-network
│   ├── oled.rs             // JSON-RPC HTTP client for peach-oled
│   ├── state_machine.rs    // state machine & state_changer()
│   ├── states.rs           // state-specific logic called by state machine
│   ├── stats.rs            // JSON-RPC HTTP client for peach-stats
│   └── structs.rs          // data types used by RPC clients

Button Code Mappings

0 => Center,  
1 => Left,  
2 => Right,  
3 => Up,  
4 => Down,  
5 => A,  
6 => B

States

Home(0),        // home menu
Home(1),        // networking selected
Home(2),        // system stats selected
Home(3),        // display off selected
Home(4),        // shutdown selected 
Logo,           // logo splash screen
Network,        // network device view
NetworkConf(0), // network configuration menu
NetworkConf(1), // client mode selected
NetworkConf(2), // access point mode selected
NetworkMode(0), // client mode activated
NetworkMode(1), // access point mode activated
OledPower(0),   // oled display off
OledPower(1),   // oled display on
Reboot,         // rebooting
Shutdown,       // shutting down
Stats,          // system statistics view

Setup

Clone this repo:

git clone https://github.com/peachcloud/peach-menu.git

Move into the repo and compile:

cd peach-menu
cargo build --release

Run the binary:

./target/target/peach-menu

Note: Will currently panic if peach_buttons is not running (connection to ws server fails).

Environment

The JSON-RPC HTTP server address and port for the OLED microservice can be configured with the PEACH_OLED_SERVER environment variable:

export PEACH_OLED_SERVER=127.0.0.1:5000

When not set, the value defaults to 127.0.0.1:5112.

Logging is made available with env_logger:

export RUST_LOG=info

Other logging levels include debug, warn and error.

Resources

This work was made much, much easier by the awesome blog post titled Pretty State Machine Patterns in Rust by hoverbear. Thanks hoverbear!

Licensing

AGPL-3.0

peach-monitor

GitHub logo Build Status Version badge

Monitor network data usage and set alert flags based on user-defined thresholds.

peach-monitor is a CLI tool capable of running as a one-shot data store updater or as a daemon for continually updating data usage alert flags.

The utility is intended to be run with the --save flag prior to each system reboot or shutdown. This allows network transmission totals (upload and download) to be persisted to the filesystem in the form of a JSON data store.

When the --update flag is set, peach-monitor retrieves user-defined alert thresholds from the data store, calculates the latest data usage statistics and sets alert flags accordingly. These flag values can be accessed from other parts of the PeachCloud system to alert the user (for example, by peach-web for web application display).

The --daemon flag executes the --update functionality in a loop and is intended to be run as a background process for convenient alert flag updates. The optional --interval argument defines the frequency with which the alert flags are updated. The default update frequency is once every 60 seconds.

The --iface argument is used to define the network interface from which to retrieve network traffic data. This defaults to wlan0 if not defined.

Usage

peach-monitor [FLAGS] [OPTIONS]

FLAGS:
    -d, --daemon     Run daemon
    -h, --help       Prints help information
    -s, --save       Save latest usage totals to file
    -u, --update     Update alert flags
    -V, --version    Prints version information

OPTIONS:
    -i, --iface <iface>    Define network interface [default: wlan0]
    -t, --interval <interval>    Define time interval for updating alert flags (seconds) [default: 60]

Data Store

~/.local/share/peachcloud

.
└── net
    ├── alert.json          // programatically-defined alert flags
    ├── notify.json         // user-defined alert thresholds
    └── traffic.json        // network transmission totals

Alert Types

peach-monitor defines warning and cutoff thresholds and corresponding alert flags for both received and transmitted network data. The cutoff thresholds are intended to allow data-intensive processes such as Scuttlebutt replication to be enabled and disabled dynamically.

Debian Packaging

A systemd service file and Debian maintainer scripts are included in the debian directory, allowing peach-monitor to be easily bundled as a Debian package (.deb). The cargo-deb crate can be used to achieve this.

Install cargo-deb:

cargo install cargo-deb

Move into the repo:

cd peach-monitor

Build the package:

cargo deb

The output will be written to target/debian/peach-monitor_0.1.0_arm64.deb (or similar).

Install the package as follows:

sudo dpkg -i target/debian/peach-monitor_0.1.0_arm64.deb

The service will be automatically enabled and started.

Uninstall the service:

sudo apt-get remove peach-monitor

Remove configuration files (not removed with apt-get remove):

sudo apt-get purge peach-monitor

Roadmap

  • Add disk-usage tracking and alerts

Licensing

AGPL-3.0

peach-network

GitHub logo Build Status Version badge

Networking microservice module for PeachCloud. Query and configure device interfaces using JSON-RPC over HTTP.

Interaction with wireless interfaces occurs primarily through the wpactrl crate which provides "a pure-Rust lowlevel library for controlling wpasupplicant remotely". This approach is akin to using wpa_cli (a WPA command line client).

Note: This module is a work-in-progress.

JSON-RPC API

Methods for retrieving data:

MethodParametersDescription
available_networksifaceList SSID, flags (security), frequency and signal level for all networks in range of given interface
idiface, ssidReturn ID of given SSID
ipifaceReturn IP of given network interface
pingRespond with success if microservice is running
rssiifaceReturn average signal strength (dBm) for given interface
rssi_percentifaceReturn average signal strength (%) for given interface
saved_networksList all networks saved in wpasupplicant config
ssidifaceReturn SSID of currently-connected network for given interface
stateifaceReturn state of given interface
statusifaceReturn status parameters for given interface
trafficifaceReturn network traffic for given interface

Methods for modifying state:

MethodParametersDescription
activate_apActivate WiFi access point (stop wpa_supplicant and start hostapd and dnsmasq)
activate_clientActivate WiFi client connection (stop hostapd and dnsmasq and start wpa_supplicant)
addssid, passAdd WiFi credentials to wpa_supplicant.conf
check_ifaceRun AP / client-mode configuration script
connectid, ifaceDisable other networks and attempt connection with AP represented by given id
deleteid, ifaceRemove WiFi credentials for given network id and interface
disableid, ifaceDisable connection with AP represented by given id
disconnectifaceDisconnect given interface
modifyid, iface, passwordSet a new password for given network id and interface
reassociateifaceReassociate with current AP for given interface
reconfigureForce wpa_supplicant to re-read its configuration file
reconnectifaceDisconnect and reconnect given interface
saveSave configuration changes to wpa_supplicant.conf

API Documentation

API documentation can be built and served with cargo doc --no-deps --open. This set of documentation is intended for developers who wish to work on the project or better understand the API of the src/network.rs module.

Directory Tree

.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│   ├── error.rs        // custom NetworkError type & From implementations
│   ├── lib.rs          // RPC server, methods & tests
│   ├── main.rs         // init logger, call run() & catch application errors
│   └── network.rs      // logic for network methods exposed via RPC

Setup

Clone this repo:

git clone https://github.com/peachcloud/peach-network.git

Move into the repo and compile:

cd peach-network
cargo build --release

Run the binary (sudo needed to satisfy permission requirements):

sudo ./target/release/peach-network

Environment

The JSON-RPC HTTP server address and port can be configured with the PEACH_NETWORK_SERVER environment variable:

export PEACH_NETWORK_SERVER=127.0.0.1:5000

When not set, the value defaults to 127.0.0.1:5110.

Logging is made available with env_logger:

export RUST_LOG=info

Other logging levels include debug, warn and error.

Example Usage

Retrieve IP address for wlan0

With microservice running, open a second terminal window and use curl to call server methods:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "get_ip", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5000

Server responds with:

{"jsonrpc":"2.0","result":"192.168.1.21","id":1}

Retrieve SSID of connected access point for wlan1

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "get_ssid", "params" : {"iface": "wlan1" }, "id":1 }' 127.0.0.1:5000

Server response when interface is connected:

{"jsonrpc":"2.0","result":"Home","id":1}

Server response when interface is not connected:

{"jsonrpc":"2.0","error":{"code":-32003,"message":"Failed to retrieve SSID for wlan1. Interface may not be connected."},"id":1}

Retrieve list of SSIDs for all networks in range of wlan0

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "scan_networks", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5000

Server response when interface is connected:

{"jsonrpc":"2.0","result":"[\"Home\",\"TP-LINK_254700\"]","id":1}

Server response when interface is not connected:

{"jsonrpc":"2.0","error":{"code":-32006,"message":"No networks found in range of wlan0"},"id":1}

Retrieve network traffic statistics for wlan1

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "get_traffic", "params" : {"iface": "wlan1" }, "id":1 }' 127.0.0.1:5000

Server response if interface exists:

{"jsonrpc":"2.0","result":"{\"received\":26396361,\"transmitted\":22352530}","id":1}

Server response when interface is not found:

{"jsonrpc":"2.0","error":{"code":-32004,"message":"Failed to retrieve network traffic for wlan3. Interface may not be connected"},"id":1}

Licensing

AGPL-3.0

peach-oled

GitHub logo Build Status Version badge

OLED microservice module for PeachCloud. Write to a 128x64 OLED display with SDD1306 driver (I2C) using JSON-RPC over HTTP.

JSON-RPC API

MethodParametersDescription
clearClear the display buffer
drawbytes, width, height, x_coord, y_coordDraw graphic to display buffer for given byte array, dimensions and co-ordinates
flushFlush the display
pingRespond with success if microservice is running
writex_coord, y_coord, string, font_sizeWrite message to display buffer for given co-ordinates using given font size

peach-oled allows text to be written with the following font sizes:

Font Sizes
6x8
6x12
8x16
12x16

Directory Tree

.
├── Cargo.lock
├── Cargo.toml
├── docs
│   └── images
│       └── peachcloud_oled.jpg
├── README.md
├── src
│   ├── error.rs        // custom OledError type & From implementations
│   ├── lib.rs          // RPC server, methods & tests (includes OLED logic)
│   └── main.rs         // init logger, call run() & catch application errors

Setup

Clone this repo:

git clone https://github.com/peachcloud/peach-oled.git

Move into the repo and compile:

cd peach-oled
cargo build --release

Run the binary:

./target/release/peach-oled

Environment

The JSON-RPC HTTP server address and port can be configured with the PEACH_OLED_SERVER environment variable:

export PEACH_OLED_SERVER=127.0.0.1:5000

When not set, the value defaults to 127.0.0.1:5112.

Logging is made available with env_logger:

export RUST_LOG=info

Other logging levels include debug, warn and error.

Example Usage

Write Text to the OLED Display

With microservice running, open a second terminal window and use curl to call server methods:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "write", "params" : {"x_coord": 0, "y_coord": 0, "string": "Welcome to PeachCloud", "font_size": "6x8" }, "id":1 }' 127.0.0.1:5112

Server responds with:

{"jsonrpc":"2.0","result":success","id":1}

OLED will remain blank because no flush command has been issued.

Write to the second line of the display:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "write", "params" : {"x_coord": 0, "y_coord": 8, "string": "Born in cypherspace", "font_size": "6x12" }, "id":1 }' 127.0.0.1:5112

Flush the display:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "flush", "id":1 }' 127.0.0.1:5112

OLED display shows:

Welcome to PeachCloud!
Born in cypherspace

Validation checks are performed for all three parameters: x_coord, y_coord and string. An appropriate error is returned if the validation checks are not satisfied:

{"jsonrpc":"2.0","error":{"code":1,"message":"Validation error: coordinate x out of range 0-128: 129."},"id":1}

{"jsonrpc":"2.0","error":{"code":1,"message":"validation error","data":"y_coord not in range 0-57"},"id":1}

{"jsonrpc":"2.0","error":{"code":1,"message":"Validation error: string length 47 out of range 0-21."},"id":1}

An error is returned if one or all of the expected parameters are not supplied:

{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params: missing field font_size."},"id":1}


Draw Graphic to the OLED Display

With microservice running, open a second terminal window and use curl to call server methods:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "draw", "params" : {"bytes": [30, 0, 33, 0, 64, 128, 128, 64, 140, 64, 140, 64, 128, 64, 64, 128, 33, 0, 30, 0], "width": 10, "height": 10, "x_coord": 32, "y_coord": 32}, "id":1 }' 127.0.0.1:5112

Server responds with:

{"jsonrpc":"2.0","result":success","id":1}

OLED will remain blank because no flush command has been issued.

Flush the display:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "flush", "id":1 }' 127.0.0.1:5112

OLED display shows a 10x10 graphic of a dot inside a circle.

No validation checks are currently performed on the parameters of the draw RPC, aside from type-checks when the parameters are parsed.


Clear the Display

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "clear", "id":1 }' 127.0.0.1:5112

Server responds with:

{"jsonrpc":"2,0","result":"success","id":1}

Licensing

AGPL-3.0

peach-stats

GitHub logo Build Status Version badge

System statistics microservice module for PeachCloud. Provides a JSON-RPC wrapper around the probes and systemstat crates.

JSON-API

MethodDescriptionReturns
cpu_statsCPU statisticsuser, system, nice, idle
cpu_stats_percentCPU statistics as percentagesuser, system, nice, idle
disk_usageDisk usage statistics (array of disks)filesystem, one_k_blocks, one_k_blocks_used, one_k_blocks_free, used_percentage, mountpoint
load_averageLoad average statisticsone, five, fifteen
mem_statsMemory statisticstotal, free, used
uptimeSystem uptimesecs, nanos

Directory Tree

.
├── Cargo.lock
├── Cargo.toml
├── README.md
└── src
    ├── error.rs        // custom StatError type & From implementations
    ├── lib.rs          // RPC server, methods & tests
    ├── main.rs         // init logger, call run() & catch application errors
    ├── stats.rs        // logic for stats methods exposed via RPC
    └── structs.rs      // data types for stats

Setup

Clone this repo:

git clone https://github.com/peachcloud/peach-stats.git

Move into the repo and compile a release build:

cd peach-stats
cargo build --release

Run the binary:

./target/release/peach-stats

Environment

The JSON-RPC HTTP server address and port can be configured with the PEACH_STATS_SERVER environment variable:

export PEACH_STATS_SERVER=127.0.0.1:5000

When not set, the value defaults to 127.0.0.1:5113.

Logging is made available with env_logger:

export RUST_LOG=info

Other logging levels include debug, warn and error.

Example Usage

Get CPU Statistics

With microservice running, open a second terminal window and use curl to call server methods:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "cpu_stats", "id":1 }' 127.0.0.1:5113

Server responds with:

{"jsonrpc":"2.0","result":"{\"user\":4661083,\"system\":1240371,\"idle\":326838290,\"nice\":0}","id":1}

Get System Uptime

With microservice running, open a second terminal window and use curl to call server methods:

curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "uptime", "id":1 }' 127.0.0.1:5113

Server responds with:

{"jsonrpc":"2.0","result":"{\"secs\":840968,\"nanos\":0}","id":1}

Licensing

AGPL-3.0

Web Interface

GitHub logo

peach-web provides a web interface for monitoring and interacting with the PeachCloud device. This allows administration of the single-board computer (ie. Raspberry Pi) running PeachCloud, as well as the ssb-server and related plugins.

Design

peach-web is written primarily in Rust and presents a web interface for interacting with the device. The stack currently consists of Rocket (Rust web framework), Tera (Rust template engine inspired by Jinja2 and the Django template language), HTML, CSS and JavaScript. Additional functionality is provided by JSON-RPC clients for the peach-network and peach-stats microservices.

HTML is rendered server-side. Request handlers call JSON-RPC microservices and serve HTML and assets. A JSON API is exposed for remote calls and dynamic client-side content updates via vanilla JavaScript following unobstructive design principles. A basic Websockets server is included, though is not currently utilised. Each Tera template is passed a context object. In the case of Rust, this object is a struct and must implement Serialize. The fields of the context object are available in the context of the template to be rendered.

Directory Tree

.
├── Cargo.lock
├── Cargo.toml
├── docs
│   ├── api_docs.md
│   ├── FEATURES.md
│   ├── js_docs.md
│   └── RESOURCES.md
├── .gitignore
├── README.md
├── Rocket.toml
├── src
│   ├── device.rs
│   ├── error.rs
│   ├── lib.rs
│   ├── main.rs
│   ├── network.rs
│   ├── stats.rs
│   ├── structs.rs
│   ├── tests.rs
│   └── ws.rs
├── static
│   ├── css
│   │   ├── peachcloud.css
│   │   └── _variables.css
│   ├── favicon.ico
│   ├── icons
│   ├── js
│   │   ├── network_card.js
│   │   ├── shutdown_menu.js
│   └── templates
│       ├── base.html.tera
│       ├── device.html.tera
│       ├── index.html.tera
│       ├── nav.html.tera
│       ├── network_add.html.tera
│       ├── network_card.html.tera
│       ├── network_detail.html.tera
│       ├── network_list.html.tera
│       ├── network_modify.html.tera
│       ├── not_found.html.tera
│       └── shutdown.html.tera

Environment

The web application deployment mode is configured with the ROCKET_ENV environment variable:

export ROCKET_ENV=stage

Other deployment modes are dev and prod. Read the Rocket Environment Configurations docs for further information.

The WebSocket server port can be configured with PEACH_WEB_WS environment variable:

export PEACH_WEB_WS=2333

When not set, the value defaults to 5115.

Logging is made available with env_logger:

export RUST_LOG=info

Other logging levels include debug, warn and error.

Setup

Clone this repo:

git clone https://github.com/peachcloud/peach-web.git

Move into the repo and compile:

cd peach-web
cargo build --release

Run the tests:

cargo test

Run the binary:

./target/release/peach-web

Note: Networking functionality requires peach-network microservice to be running.

peach-patterns

GitHub logo

A pattern library for building and maintaining PeachCloud user interfaces.

index.html currently serves as the primary aggregator and displayer of patterns in the form of atoms and molecules (see Atomic Design by Brad Frost for more information on this approach to building design systems).

css/css_class_names contains a simple list of all the custom css class names used in the PeachCloud design system. This list builds on css/_variables.css, which contains css variables drawn from the Tachyons library. The content of css/_variables.css will be pruned of unneeded code once the design system stabilizes.

css/peachcloud.css contains all the custom css class definitions used in the PeachCloud design system.

Note: This is a work-in-progress.

Directory Tree

.
├── css
│   ├── css_class_names     // list of all custom class names
│   ├── peachcloud.css      // custom css class definitions and styles
│   └── _variables.css      // css variables from Tachyons
├── icons                   // all icon files (svg & png)
├── index.html              // markup of pattern library
├── README.md

Setup

For now you can simply clone the repo and open the index.html file in your browser to view the pattern library.

Licensing

AGPL-3.0

Compilation

Since the majority of PeachCloud is written in the Rust programming language, a compiler and associated toolchain(s) is required to build the software from source. Visit the rustup website to download the Rust toolchain installer. In addition to the default stable installation of Rust, many PeachCloud crates require the nightly toolchain channel in order to compile. Instructions for installing and updating toolchains can be found in the README of the rustup GitHub repo.

Cross-Compilation

While PeachCloud crates can be compiled directly on the Raspberry Pi or equivalent single board computer, this process is resource intensive and relatively slow - especially when compiling release builds. Cross-compilation is an effective means of leveraging greater compute resources to reduce compilation time.

These instructions cover cross-compilation for Debian Buster running on a Raspberry Pi 3B+, using a host machine running Debian Stretch with an x86_64 architecture:

Install target platform:

rustup target add aarch64-unknown-linux-gnu

Install toolchain:

rustup toolchain install nightly-aarch64-unknown-linux-gnu

Install aarch64-linux-gnu-gcc:

sudo apt-get install gcc-aarch64-linux-gnu

Configure the linker:

export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/aarch64-linux-gnu-gcc

Alternatively, create a file named config in the ~/.cargo directory of the home user and add the following:

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
objcopy = { path ="aarch64-linux-gnu-objcopy" }
strip = { path ="aarch64-linux-gnu-strip" }

The objcopy and strip parameters are needed by cargo deb when cross-compiling Debian packages.

Compile release build:

cargo build --release --target=aarch64-unknown-linux-gnu

The generated binary will be saved at target/aarch64-unknown-linux-gnu/release/name_of_crate

Debian Packaging

The microservices comprising the PeachCloud software suite are packaged for easy deployment and maintainance on Debian and derivative operating systems.

Each microservice repository includes a debian directory which includes a systemd service file and Debian maintainer scripts, including postinst, postrm and prerm scripts. These scripts define behavior for installing and uninstalling the respective services. deb packages are created using the cargo-deb tool (crate).

Install cargo-deb:

cargo install cargo-deb

Create the package:

cargo deb --target aarch64-unknown-linux-gnu

Note: the correct linker, objcopy and strip parameters must be defined in ~/.cargo/config for the above command to execute successfully. Visit the Compilation page and look under 'Configure the linker' for more details.

Install the package:

sudo dpkg -i peach-network_0.1.0_arm64.deb

The service will be automatically enabled and started.

Uninstall the package:

sudo apt-get remove peach-network

Remove configuration files (not removed with apt-get remove):

sudo apt-get purge peach-network

Configuration

The microservices and other components comprising the PeachCloud software are configurable via the following environment variables:

MicroserviceVariableDescriptionDefault
peach-networkPEACH_NETWORK_SERVERHTTP server address and port for JSON-RPC127.0.0.1:5110
peach-buttonsPEACH_BUTTONS_SERVERWebSocket server address and port for JSON-RPC127.0.0.1:5111
peach-oledPEACH_OLED_SERVERHTTP server address and port for JSON-RPC127.0.0.1:5112
peach-statsPEACH_STATS_SERVERHTTP server address and port for JSON-RPC127.0.0.1:5113
peach-webROCKET_ENVWeb application deployment modeprod
peach-webROCKET_TEMPLATE_DIRTera template directorystatic/templates
peach-webPEACH_WEB_WSWebSocket server port5115

Contributor's Guide

Anyone who feels excited about PeachCloud is encouraged to contact @glyph on Scuttlebutt or via email to discuss potential contributions. Please include details on what attracts you to PeachCloud, how you might like to contribute and what relevant experience you have. It's worth noting that you don't have to be a programmer to offer meaningful contributions.

SSB: @HEqy940T6uB+T+d9Jaa58aNfRzLx9eRWqkZljBmnkmk=.ed25519
Email: glyph@mycelial.technology

Processes

Coordination

Project management and coordination take place on Asana. This service allows the creation and assignment of tasks - as well as the ability to track task completion and share task-related notes among team members. Upon invitation to contribute to PeachCloud, new contributors will be sent an email invitation to join the MVP Development project on Asana.

Signal messenger is used for day-to-day communications, process-related queries and interpersonal check-ins. Jitsi Meet video calls are held once every two weeks and prior to the onboarding of new developers. Mumble is used for audio calls when one or several contributors are on slow or degraded internet connections.

Code

PeachCloud repositories are based on GitHub and are collected under the PeachCloud organization. New contributors will be added to the 'contributors' team and given appropriate access permissions.

GitHub issues are used to discuss repository-specific bugs and features.

Contributions to repositories are made in the form of pull-requests from forked repositories. Pull-requests bundle multiple commits and offer an opportunity to request comment or code review from fellow contributors. Contributors are encouraged to submit concise yet detailed descriptions when submitting pull-requests, and may even add screenshots or other images when desired. Over time, the pull-request history helps to tell the story of component development at a greater level of granularity than single commits.

Developer Diaries

Contributors to PeachCloud may wish to create a 'dev diary' thread on Scuttlebutt, though this is entirely optional and up to each individual. Dev diaries are a fun way to share and celebrate project progress with fellow Butts. A personal diary / log may also be kept to track work tasks and rhythms, and to offer a document for reflection.

Licensing

AGPL-3.0