diff bin/attic/captureDevice @ 2376:4556eebe5d73

topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author drewp@bigasterisk.com
date Sun, 12 May 2024 19:02:10 -0700
parents bin/captureDevice@8516a39eedc9
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/attic/captureDevice	Sun May 12 19:02:10 2024 -0700
@@ -0,0 +1,199 @@
+#!bin/python
+"""
+Operate a motorized light and take pictures of it in every position.
+"""
+from rdflib import URIRef
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks, Deferred
+
+import logging
+import optparse
+import os
+import time
+import treq
+import cyclone.web, cyclone.websocket, cyclone.httpclient
+from light9.metrics import metrics, metricsRoute
+from run_local import log
+from cycloneerr import PrettyErrorHandler
+
+from light9.namespaces import L9, RDF
+from light9 import networking, showconfig
+from rdfdb.syncedgraph import SyncedGraph
+from light9.paint.capture import writeCaptureDescription
+from light9.effect.settings import DeviceSettings
+from light9.collector.collector_client import sendToCollector
+from rdfdb.patch import Patch
+from light9.zmqtransport import parseJsonMessage
+
+
+
+class Camera(object):
+
+    def __init__(self, imageUrl):
+        self.imageUrl = imageUrl
+
+    def takePic(self, uri, writePath):
+        log.info('takePic %s', uri)
+        return treq.get(
+            self.imageUrl).addCallbacks(lambda r: self._done(writePath, r),
+                                        log.error)
+
+    @inlineCallbacks
+    def _done(self, writePath, response):
+        jpg = yield response.content()
+        try:
+            os.makedirs(os.path.dirname(writePath))
+        except OSError:
+            pass
+        with open(writePath, 'w') as out:
+            out.write(jpg)
+        log.info('wrote %s', writePath)
+
+
+def deferSleep(sec):
+    d = Deferred()
+    reactor.callLater(sec, d.callback, None)
+    return d
+
+
+class Capture(object):
+    firstMoveTime = 3
+    settleTime = .5
+
+    def __init__(self, graph, dev):
+        self.graph = graph
+        self.dev = dev
+
+        def steps(a, b, n):
+            return [round(a + (b - a) * i / n, 5) for i in range(n)]
+
+        startTime = time.time()
+        self.captureId = 'cap%s' % (int(startTime) - 1495170000)
+        self.toGather = []
+
+        #quantum
+        rxSteps = steps(.06, .952, 10)
+        rySteps = steps(0.1, .77, 5)
+        zoomSteps = steps(.12, .85, 3)
+        # aura
+        rxSteps = steps(0.15, .95, 10)
+        rySteps = steps(0, .9, 5)
+        zoomSteps = steps(.6, .9, 3)
+
+        row = 0
+        for ry in rySteps:
+            xSteps = rxSteps[:]
+            if row % 2:
+                xSteps.reverse()
+            row += 1
+            for rx in xSteps:
+                for zoom in zoomSteps:
+                    self.toGather.append(
+                        DeviceSettings(
+                            graph,
+                            [
+                                (dev, L9['rx'], rx),
+                                (dev, L9['ry'], ry),
+                                (dev, L9['color'], '#ffffff'),
+                                (dev, L9['zoom'], zoom),
+                                #(dev, L9['focus'], 0.13),
+                            ]))
+
+        self.devTail = dev.rsplit('/')[-1]
+        self.session = URIRef('/'.join(
+            [showconfig.showUri(), 'capture', self.devTail, self.captureId]))
+        self.ctx = URIRef(self.session + '/index')
+
+        self.graph.patch(
+            Patch(addQuads=[
+                (self.session, RDF.type, L9['CaptureSession'], self.ctx),
+            ]))
+
+        self.numPics = 0
+        self.settingsCache = set()
+        self.step().addErrback(log.error)
+
+    def off(self):
+        return sendToCollector(client='captureDevice',
+                               session='main',
+                               settings=DeviceSettings(self.graph, []))
+
+    @inlineCallbacks
+    def step(self):
+        if not self.toGather:
+            yield self.off()
+            yield deferSleep(1)
+            reactor.stop()
+            return
+        settings = self.toGather.pop()
+
+        log.info('[%s left] move to %r', len(self.toGather), settings)
+        yield sendToCollector(client='captureDevice',
+                              session='main',
+                              settings=settings)
+
+        yield deferSleep(self.firstMoveTime if self.numPics ==
+                         0 else self.settleTime)
+
+        picId = 'pic%s' % self.numPics
+        path = '/'.join(['capture', self.devTail, self.captureId, picId
+                        ]) + '.jpg'
+        uri = URIRef(self.session + '/' + picId)
+
+        yield camera.takePic(uri, os.path.join(showconfig.root(), path))
+        self.numPics += 1
+
+        writeCaptureDescription(self.graph, self.ctx, self.session, uri,
+                                self.dev, path, self.settingsCache, settings)
+
+        reactor.callLater(0, self.step)
+
+
+camera = Camera(
+    'http://plus:8200/picamserve/pic?res=1080&resize=800&iso=800&redgain=1.6&bluegain=1.6&shutter=60000&x=0&w=1&y=0&h=.952'
+)
+
+
+class Attrs(PrettyErrorHandler, cyclone.web.RequestHandler):
+
+    @metrics('set_attr').time()
+    def put(self):
+        client, clientSession, settings, sendTime = parseJsonMessage(
+            self.request.body)
+        self.set_status(202)
+
+
+def launch(graph):
+
+    cap = Capture(graph, dev=L9['device/aura5'])
+    reactor.listenTCP(networking.captureDevice.port,
+                      cyclone.web.Application(handlers=[
+                          (r'/()', cyclone.web.StaticFileHandler, {
+                              "path": "light9/web",
+                              "default_filename": "captureDevice.html"
+                          }),
+                          metricsRoute(),
+                      ]),
+                      interface='::',
+                      cap=cap)
+    log.info('serving http on %s', networking.captureDevice.port)
+
+
+def main():
+    parser = optparse.OptionParser()
+    parser.add_option("-v",
+                      "--verbose",
+                      action="store_true",
+                      help="logging.DEBUG")
+    (options, args) = parser.parse_args()
+    log.setLevel(logging.DEBUG if options.verbose else logging.INFO)
+
+    graph = SyncedGraph(networking.rdfdb.url, "captureDevice")
+
+    graph.initiallySynced.addCallback(lambda _: launch(graph)).addErrback(
+        log.error)
+    reactor.run()
+
+
+if __name__ == '__main__':
+    main()