collapse

Welcome!



Welcome to Robot Rebels, an online robot maker community.

Register today to post your projects, ask questions, share knowledge and meet like-minded people from around the world.


The RobotRebel.org Community

Author Topic: RC PDU  (Read 238 times)

mogul

  • Hot glue gunslinger
  • Member
  • *
  • Posts: 135
  • This is a good day!
RC PDU
« on: March 22, 2017, 04:39:26 PM »
A small remote controlled (wifi) power distribution unit.

Board takes 12V DC as input. Has two step-down regulators, 5V and 3.3V

2017-03-22 21.25.27.jpg
*2017-03-22 21.25.27.jpg (93.35 kB . 800x474 - viewed 57 times)

Board holds an ESP8266
2017-03-22 21.25.55.jpg
*2017-03-22 21.25.55.jpg (108 kB . 800x520 - viewed 49 times)

and the backside is ugly
2017-03-22 21.26.20.jpg
*2017-03-22 21.26.20.jpg (129.75 kB . 800x530 - viewed 48 times)
And the schematic
PDU-ESP8266-RPi-server (1).png
*PDU-ESP8266-RPi-server (1).png (42.21 kB . 800x623 - viewed 35 times)
added a reset switch, and since the board was made so compact, it has no room for ins for in-system-programming, so I soldered extra long pins on the ESP-12E module. Now I can hook my USB interface to top top side of the ESP module.
2017-03-24 22.11.52.jpg
*2017-03-24 22.11.52.jpg (83.8 kB . 775x768 - viewed 32 times)
Software is written in python. I find it very pleasing to use micropython for microcontrollers.

When booted it act as a webserver, with an additional timer. wait two days and it will boot the RPi, or fire a web request to get it going on demand:
status
Code: [Select]
mogul@linuxine:~$ curl razfs2b-pwr
{"timer": 171841, "stage": "sleep", "RPi": 1}

turn on
Code: [Select]
mogul@linuxine:~$ curl razfs2b-pwr/on
ok

then use status again to wast it step through stages to reach on
Code: [Select]
mogul@linuxine:~$ curl razfs2b-pwr
{"timer": 0, "stage": "on", "RPi": 1}



Not perfectly pleased with the structure of the code, but not too bad either. I have split the code into several modules for easy reuse. First a module to initialize a wifi station:
wifi.py
Code: [Select]
import network
import time

wlan = network.WLAN(network.STA_IF)
network.WLAN(network.AP_IF).active(False)

def start():
    import wifi_cfg
   
    wlan.active(True)
    wlan.disconnect()

    try:
        wlan.config(dhcp_hostname=wifi_cfg.hostname)
    except OSError as e:
        print("WARN: set dhcp_hostname:", str(e))

    wlan.connect(wifi_cfg.ssid, wifi_cfg.password)

def wait_for_join(timeout=5):
    retry = timeout
    while retry and not wlan.isconnected():
        time.sleep(1)
        retry =- 1
    return wlan.isconnected()

def get_info():
    return wlan.ifconfig()

then a module to act as a web-server:
phttpd.py
Code: [Select]
import usocket
import uselect

class phttpd:
    def __init__(self,  port):
        addr = usocket.getaddrinfo("0.0.0.0", port)[0][-1]
        self._sock = usocket.socket()
        self._sock.bind(addr)
        self._sock.listen(2)
        self._poll = uselect.poll()
        self._poll.register(self._sock, uselect.POLLIN)
        self._methods = {"GET":{}}


    def register(self, method, uri, cb):
        self._methods[method][uri] = cb


    def _load_request(self, stream):
        l = [x.strip() for x in stream.readline().decode("utf-8").split(' ')]

        # eat and discard remaining headers
        while stream.readline().strip():
            pass

        return (l[:2]) # http method and uri

       
    def poll(self):
        if self._poll.poll(0):
            (c_stream, c_addr) = self._sock.accept()
            (m, u) = self._load_request(c_stream)
            print("%s: %s %s" % (c_addr[0], m, u))

            try:
                cb = self._methods[m][u]
            except KeyError:
                c_stream.write("HTTP/1.0 404 Not Found\n\n")
            else:
                c_stream.write("HTTP/1.0 200 ok\n\n%s\n" % cb())

            c_stream.close()
and finally the sequencer:
RPi_sequencer.py
Code: [Select]
import gc
import time
import machine
from phttpd import phttpd
import ujson

class timer:
    def __init__(self):
        self.t = 0
    def set(self, sec):
        self.t = time.time() + sec
    def get(self):
        return max(self.t - time.time(), 0)
    def timeout(self):
        return self.t and time.time() > self.t

class state:
    def __init__(self, s):
        self.s = s
    def set(self,s):
        print("[%d] state %s => %s" % (int(time.time()), self.s, s))
        self.s = s
    def get(self):
        return self.s
    def test(self, s):
        return s == self.s

class sequencer:
    def __init__(self, scheduled_interval):
        self.RPiSense = machine.Pin(12, machine.Pin.IN, machine.Pin.PULL_UP)
        self.hddPwr = machine.Pin(13, machine.Pin.OUT)
        self.RPiPwr = machine.Pin(14, machine.Pin.OUT)
        self.stage = state("off")
        self.timer = timer()
        self.scheduled_interval = scheduled_interval
        self.poll()

    def get_state(self):
        return ujson.dumps({
          'stage': self.stage.get(),
          'RPi':   self.RPiSense.value(),
          "timer": self.timer.get()
        })

    def on(self):
        if self.stage.test("sleep"):
            self.stage.set("wakeup")
            return "ok"
        else:
            return "not sleeping"

    def force_off(self):
        self.stage.set("off")
        return "ok"

    def poll(self):
        if self.stage.test("off"): # all off, wait for timed wakeup
            self.hddPwr.value(0)
            self.RPiPwr.value(0)
            self.timer.set(self.scheduled_interval)
            self.stage.set("sleep")

        if self.stage.test("sleep") and self.timer.timeout(): # sleep is over
            self.stage.set("wakeup")

        if self.stage.test("wakeup"): # power up hdd
            self.hddPwr.value(1)
            self.timer.set(15)
            self.stage.set("hdd spin up")

        if self.stage.test("hdd spin up") and self.timer.timeout(): # power up RPi
            self.RPiPwr.value(1)
            self.timer.set(10)
            self.stage.set("RPi boot up")

        if self.stage.test("RPi boot up") and self.timer.timeout(): # RPi now booted
            self.stage.set("on")

        if self.stage.test("on") and self.RPiSense.value() == 0: # RPi signaled poweroff
            self.timer.set(20)
            self.stage.set("showdown initiated")

        if self.stage.test("showdown initiated") and self.RPiSense.value() == 1: # RPi canceled poweroff
            self.stage.set("on")

        if self.stage.test("showdown initiated") and self.timer.timeout(): # power off
            self.stage.set("off")

p = sequencer(3600*24*2)
w = phttpd(80)

def start():
    w.register('GET', '/', p.get_state)
    w.register('GET', '/on', p.on)
    w.register('GET', '/FORCE_OFF', p.force_off)

    while True:
        w.poll()
        p.poll()
        gc.collect()

To make it start on power up:
main.py
Code: [Select]
import wifi
import webrepl
import RPi_sequencer

wifi.start()
wifi.wait_for_join()
print("our_ip", wifi.get_info()[0])

webrepl.start()
RPi_sequencer.start()

wifi and webrepl take two configuration files:
wifi_cfg.py
Code: [Select]
ssid='mogul-net'
password='hotglue'
hostname='RPi-pwr'
webrepl_cfg.py
Code: [Select]
PASS='ducttape'

To make the RPi power it self off I have added a line to the kernel configuration, done on
/boot/config.txt
Code: [Select]
# GIPIO=22, goes low when ready for power cut
dtoverlay=gpio-poweroff,gpiopin=22,active_low

and then connected RPi GIPIO=22 to ESP8266 GPIO-12.
« Last Edit: April 29, 2017, 10:28:49 AM by mogul »

 

* Search


* Recent Topics

Encoders Really? by DangerousThing
[Today at 05:37:59 AM]


Blockchains, Ethereum, and a Safer SkyNet by jinx
[June 26, 2017, 01:17:32 PM]


Z motor mount by jinx
[June 26, 2017, 04:05:25 AM]


Spinny Flowers by Impala
[June 25, 2017, 06:24:33 PM]


Automobile drag coefficient by Impala
[June 23, 2017, 01:18:46 AM]


Arduino fork by ossipee
[June 20, 2017, 03:20:37 PM]


ghetto compressor revisited by 1 what
[June 19, 2017, 04:07:09 AM]


Don Quixote Re-loaded by Gareth
[June 18, 2017, 07:10:39 AM]


Spammers by MEgg
[June 16, 2017, 11:11:26 AM]


5 min meeting timer by mogul
[June 16, 2017, 04:55:08 AM]


Picture Topic by Impala
[June 14, 2017, 05:17:43 PM]


Bluetooth Low Energy in JavaScript by Ladvien
[June 10, 2017, 05:10:21 PM]


Gait Creation Using Excel by BaldwinK
[June 08, 2017, 01:41:11 PM]


Which micro motor solution would be the strongest ? by programer786
[June 07, 2017, 02:50:31 PM]


Fun Fact by jinx
[June 07, 2017, 03:08:01 AM]

* Recent Posts

Re: Encoders Really? by DangerousThing
[Today at 05:37:59 AM]


Re: Blockchains, Ethereum, and a Safer SkyNet by jinx
[June 26, 2017, 01:17:32 PM]


Z motor mount by jinx
[June 26, 2017, 04:05:25 AM]


Spinny Flowers by Impala
[June 25, 2017, 06:24:33 PM]


Re: Blockchains, Ethereum, and a Safer SkyNet by mogul
[June 23, 2017, 01:53:15 AM]


Re: Automobile drag coefficient by Impala
[June 23, 2017, 01:18:46 AM]


Blockchains, Ethereum, and a Safer SkyNet by mtriplett
[June 22, 2017, 11:47:08 AM]


Re: Automobile drag coefficient by Impala
[June 21, 2017, 09:45:12 PM]


Re: Arduino fork by ossipee
[June 20, 2017, 03:20:37 PM]


Re: Arduino fork by mogul
[June 20, 2017, 02:28:32 PM]


Arduino fork by ossipee
[June 20, 2017, 01:35:33 PM]


Re: ghetto compressor revisited by 1 what
[June 19, 2017, 04:07:09 AM]


Re: Don Quixote Re-loaded by Gareth
[June 18, 2017, 07:10:39 AM]


Re: Spammers by MEgg
[June 16, 2017, 11:11:26 AM]


Re: 5 min meeting timer by mogul
[June 16, 2017, 04:55:08 AM]