# Marc Plano-Lesay

Random musings of a software engineer.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Shipping logs to Loki

DevFeed: [Shipping logs to Loki](<https://devfeed.tech/articles/shipping-logs-to-loki-21775.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/production-grade-esphome/02-shipping-logs-to-loki/>)

Author: Marc Plano-Lesay

Published: 2026-04-03T10:10:02Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Logging](<https://devfeed.tech/topics/logging.md>), [Monitoring](<https://devfeed.tech/topics/monitoring.md>), [Prometheus](<https://devfeed.tech/topics/prometheus.md>)

Tags: [esphome](<https://devfeed.tech/tags/esphome.md>), [iot](<https://devfeed.tech/tags/iot.md>), [logs](<https://devfeed.tech/tags/logs.md>), [loki](<https://devfeed.tech/tags/loki.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [observability](<https://devfeed.tech/tags/observability.md>), [prometheus](<https://devfeed.tech/tags/prometheus.md>), [server-sent-events](<https://devfeed.tech/tags/server-sent-events.md>), [terminal](<https://devfeed.tech/tags/terminal.md>)

### AI overview

This tutorial explains how to ship ESPHome device logs to Loki. It contrasts logs with Prometheus metrics, describes the ephemeral nature of device logs, and introduces Server-Sent Events and syslog as ways to extract logs for aggregation.

### Source excerpt

When metrics aren't the whole story In the previous post, we set up metrics collection with Prometheus. We can now see what is happening on our devices -- a sensor is failing, the WiFi signal is degrading, or the main loop is running slow. But metrics alone don't tell us why. When a device reboots, the uptime metric resets -- but what caused the reboot? When an entity fails, the _failed metric goes to 1 -- but what error occurred?

## Scraping ESPHome metrics with Prometheus

DevFeed: [Scraping ESPHome metrics with Prometheus](<https://devfeed.tech/articles/scraping-esphome-metrics-with-prometheus-21774.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/production-grade-esphome/01-scraping-esphome-metrics-with-prometheus/>)

Author: Marc Plano-Lesay

Published: 2026-03-29T03:18:27Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [esphome](<https://devfeed.tech/topics/esphome.md>), [Prometheus](<https://devfeed.tech/topics/prometheus.md>), [observability](<https://devfeed.tech/topics/observability.md>), [Monitoring](<https://devfeed.tech/topics/monitoring.md>), [Grafana](<https://devfeed.tech/topics/grafana.md>)

Tags: [devices](<https://devfeed.tech/tags/devices.md>), [esphome](<https://devfeed.tech/tags/esphome.md>), [grafana](<https://devfeed.tech/tags/grafana.md>), [iot](<https://devfeed.tech/tags/iot.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [observability](<https://devfeed.tech/tags/observability.md>), [prometheus](<https://devfeed.tech/tags/prometheus.md>)

### AI overview

A tutorial on exposing ESPHome device metrics in the OpenMetrics format and scraping them with Prometheus. It explains how observability helps monitor device state, connectivity, and diagnostic information, with Grafana mentioned for dashboards and alerting.

### Source excerpt

What is observability and why does it matter? ESPHome is an amazing tool. Devices you build with it are very useful. But how do you notice when they don't work? You would eventually notice if a temperature sensor stopped working and your climate control automations aren't working as intended. While that's not ideal, it gets worse: what about a sensor part of an alarm system, detecting that a window is open?

## Ktor: Altering served content

DevFeed: [Ktor: Altering served content](<https://devfeed.tech/articles/ktor-altering-served-content-21773.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/ktor-altering-served-content/>)

Author: Marc Plano-Lesay

Published: 2022-09-06T04:00:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Web Development](<https://devfeed.tech/topics/web-development.md>), [Netty](<https://devfeed.tech/topics/netty.md>), [HTTP](<https://devfeed.tech/topics/http.md>), [servers](<https://devfeed.tech/topics/servers.md>)

Tags: [configuration](<https://devfeed.tech/tags/configuration.md>), [html](<https://devfeed.tech/tags/html.md>), [http](<https://devfeed.tech/tags/http.md>), [js](<https://devfeed.tech/tags/js.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [ktor](<https://devfeed.tech/tags/ktor.md>), [plugin](<https://devfeed.tech/tags/plugin.md>), [plugins](<https://devfeed.tech/tags/plugins.md>), [script](<https://devfeed.tech/tags/script.md>), [server](<https://devfeed.tech/tags/server.md>), [web](<https://devfeed.tech/tags/web.md>)

### AI overview

A tutorial on creating a Ktor plugin that injects a configured script element into the head of served HTML files. It uses Ktor response-pipeline hooks to transform HTML while leaving other file formats unchanged, with Jsoup handling the HTML modification.

### Source excerpt

When serving files with Ktor, there might be times when you need to alter those files. For example, you might want to inject a script in every served HTML file. For this purpose, we can leverage plugins. Plugins can hook at different stages of the request/response pipeline: graph LR Request --> Plugin1[Plugin] Plugin1 --> Handler Handler --> Plugin2[Plugin] Plugin2 --> Response Ktor request/response pipeline Let's write a plugin that transforms a specific type of files - going with the previous example of injecting a script to every served HTML file. Our plugin needs to: Take a script URL as an input. If not provided, it won't do anything. Add that script as a <script> element in the <head> of any HTML file served by this Ktor server. Obviously, not interfere with any other file format. Let's start by defining an empty plugin and its configuration: class PluginConfiguration { var scriptUrl: String? = null } val ScriptInjectionPlugin = createApplicationPlugin( name = "ScriptInjectionPlugin", createConfiguration = ::PluginConfiguration, ) { val scriptUrl = pluginConfig.scriptUrl // The rest of our plugin goes here. } With this simple definition, we can add our plugin to a Ktor server: embeddedServer(Netty, port = 8080) { install(ScriptInjectionPlugin) { scriptUrl = "http://foo.bar/my/injected/script.js" } } Now, let's see how we can transform the body. Ktor offers a few handlers to hook into the pipeline shown above. The main ones are: onCall is fairly high level, and is mostly useful to get information about a request (e.g. to log a request). onCallReceive allows to transform data received from the client before it's processed. onCallRespond allows to transform data before sending it to the client. That's the one we're after. There are a few other handlers for specific use-cases, detailed here. Let's hook into onCallRespond, and its helper transformBody. We also need to check if the content type we're sending is HTML, otherwise, we just forward the response body as-i

## Serving static files with Ktor

DevFeed: [Serving static files with Ktor](<https://devfeed.tech/articles/serving-static-files-with-ktor-21777.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/serving-static-files-with-ktor/>)

Author: Marc Plano-Lesay

Published: 2022-09-03T09:00:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [servers](<https://devfeed.tech/topics/servers.md>), [Routing (disambiguation)](<https://devfeed.tech/topics/routing.md>), [web applications](<https://devfeed.tech/topics/web-applications.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>)

Tags: [files](<https://devfeed.tech/tags/files.md>), [handler](<https://devfeed.tech/tags/handler.md>), [html](<https://devfeed.tech/tags/html.md>), [http](<https://devfeed.tech/tags/http.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [ktor](<https://devfeed.tech/tags/ktor.md>), [plugin](<https://devfeed.tech/tags/plugin.md>), [port](<https://devfeed.tech/tags/port.md>), [route](<https://devfeed.tech/tags/route.md>), [routing](<https://devfeed.tech/tags/routing.md>), [web](<https://devfeed.tech/tags/web.md>)

### AI overview

This tutorial explains how to serve static files and nested index.html files with Ktor. It replaces the default static-file handling with a custom route that resolves files and directory fallbacks, then uses a Ktor plugin to handle trailing slashes.

### Source excerpt

Serving static files with Ktor for a static website seems easy enough: fun main() { embeddedServer(Netty, port = 8080) { routing { static { files("static-data") } } }.start(wait = true) } Done? Not quite. Opening http://localhost:8080 will only get you a 404, even if you have an index.html file in the static-data folder. You have to let Ktor know you want to opt-in serving a default file. Let's try again (omitting anything outside the static block): static { files("static-data") default("static-data/index.html") } Surely now this works? Well, kind of. The root folder will have a default index.html, but sadly if you have any sub-folders with index.html files inside, they won't be served by default - that default() function only works for the top-level folder. Let's work around that. Let's store our static-data directory into a File variable, replace the files function call by our own extension. Note that this extension will handle the fallback to index.html in all cases, so we can also remove the call to default(): val staticData = File("/path/to/static-data") static { filesWithDefaultIndex(staticData) } fun Route.filesWithDefaultIndex(dir: File) { } In there, we'll need a get handler: fun Route.filesWithDefaultIndex(dir: File) { get("{static_path...}") {} } This will catch anything inside the static path, and let us access the requested path through call.parameters.getAll("static_path"). This gets us a list of URL segments that we need to join with File.separator: val relativePath = call.parameters .getAll("static_path") ?.joinToString(File.separator) ?: return@get Now, we have three options: The requested path points to an existing file. Great! We can just return it. The requested path points to a folder. If there's an index.html file in there, let's serve it. In any other case (the requested path doesn't exist, or points to a folder without an index.html file), we let Ktor handle that (most likely returning a 404). We can easily access the corresponding local file

## Writing a Bazel rule set

DevFeed: [Writing a Bazel rule set](<https://devfeed.tech/articles/writing-a-bazel-rule-set-21771.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/creating-a-blog-with-bazel/04-writing-bazel-rule-set/>)

Author: Marc Plano-Lesay

Published: 2020-05-16T04:55:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [bazel](<https://devfeed.tech/topics/bazel.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>), [configuration](<https://devfeed.tech/topics/configuration.md>), [Java](<https://devfeed.tech/topics/java.md>), [SVG](<https://devfeed.tech/topics/svg.md>)

Tags: [bazel](<https://devfeed.tech/tags/bazel.md>), [cli](<https://devfeed.tech/tags/cli.md>), [configuration](<https://devfeed.tech/tags/configuration.md>), [java](<https://devfeed.tech/tags/java.md>), [plantuml](<https://devfeed.tech/tags/plantuml.md>), [svg](<https://devfeed.tech/tags/svg.md>)

### AI overview

A tutorial on writing and testing a Bazel rule set to run PlantUML as a command-line tool. It covers PlantUML inputs and outputs, Java JAR execution, configuration files, SVG and PNG generation, and challenges from platform-dependent font rendering and non-hermetic metadata.

### Source excerpt

This post will cover two things: How to run an arbitrary tool with Bazel (in this case, PlantUML, a tool to generate diagrams), by writing a rule set How to test this rule set. It should be mentioned that while I was working on this rule set, it became more and more apparent PlantUML is not a great candidate for this kind of integration, as its output is platform-dependent (the font rendering). Despite that, it's still a simple tool and as such its integration is simple, albeit not perfect (the rendering tests I wrote need to run on the same platform every time). PlantUML usage PlantUML is a tool that takes a text input looking like this: @startuml Alice -> Bob: SYN @enduml And outputs an image looking like this: sequenceDiagram Alice->>Bob: SYN PlantUML sample output PlantUML has multiple way of being invoked (CLI, GUI, as well as a lot of integrations with different tools), but we'll go with the easiest: a one-shot CLI invocation. It takes as inputs: A text file, representing a diagram An optional configuration file, giving control over the output It then outputs a single image file, which can be of different formats (we'll just cover SVG and PNG in this article, but adding support for other formats is trivial). PlantUML ships as a JAR file, which needs to be run with Java. An invocation generating the sample image above would look like that: java -jar plantuml.jar -tpng -p < 'mysource.puml' > 'dir/myoutput.png' Pretty straightforward: run the JAR, with a single option for the image type, pipe the content of the input file and get the output file back. The -p flag is the short form of -pipe, which we're using as using pipes is the only way of properly controlling the output path (without that, PlantUML tries to be smart and places the output next to the input). With a configuration file: java -jar plantuml.jar -tpng -config config.puml -p < 'mysource.puml' > 'dir/myoutput.png' Simple enough, right? Well, not really. PlantUML actually integrates some metadata in th

## Compiling a Kotlin application with Bazel

DevFeed: [Compiling a Kotlin application with Bazel](<https://devfeed.tech/articles/compiling-a-kotlin-application-with-bazel-21769.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/creating-a-blog-with-bazel/02-compiling-a-kotlin-application-with-bazel/>)

Author: Marc Plano-Lesay

Published: 2019-12-08T00:30:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [bazel](<https://devfeed.tech/topics/bazel.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Dagger](<https://devfeed.tech/topics/dagger.md>), [Maven](<https://devfeed.tech/topics/maven.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>)

Tags: [annotation-processor](<https://devfeed.tech/tags/annotation-processor.md>), [bazel](<https://devfeed.tech/tags/bazel.md>), [dagger](<https://devfeed.tech/tags/dagger.md>), [dependencies](<https://devfeed.tech/tags/dependencies.md>), [dependency](<https://devfeed.tech/tags/dependency.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>)

### AI overview

A tutorial on compiling a small Kotlin application with Bazel. It explains the Phosphorus application's structure, its image-comparison purpose, Maven dependencies, rules_jvm_external, tests, Dagger's annotation processor, and Kotlin integration.

### Source excerpt

This post will describe how to compile a small application written in Kotlin using Bazel, tests, as well as how to use static analyzers. Phosphorus Phosphorus is the application that this post will cover. It's a small utility that I wrote to check if an image matches a reference. If it doesn't, Phosphorus generates an image highlighting the differences. The goal is to be able to check that something generates an image in a given way, and doesn't change - at least if it's not expected. The actual usage will be covered later in this series. While it's not open-source yet, it's something I intend to do at some point. It's written in Kotlin, as a couple external dependencies ( Clikt and Dagger), as well as a few tests. This is the structure: classDiagram namespace loader { class ImageLoader { <<interface>> } class ImageIoLoader { } } namespace differ { class ImageDiffer { <<interface>> } class ImageDifferImpl { } } namespace data { class Image class DiffResult } class Phosphorus ImageIoLoader ..|> ImageLoader ImageDifferImpl ..|> ImageDiffer Phosphorus --> ImageLoader Phosphorus --> ImageDiffer Phosphorus's class diagram The differ module contains the core logic - comparing two images, and generating a DiffResult. This DiffResult contains both the straightforward result of the comparison (are the two images identical?) and an image highlighting the differences, if any. The loader package is responsible for loading and writing images. Finally, the Phosphorus class orchestrates all that, in addition to processing command line arguments with Clikt. Dependencies Phosphorus has two dependencies: Clikt, and Dagger. Both of them are available as Maven artifacts. In order to pull Maven artifacts, the Bazel team provides a set of rules called rules_jvm_external. The idea is the following: you list a bunch of Maven coordinates and repositories, the rule will fetch all of them (and their transitive dependencies) during the loading phase, and generate Bazel targets corresponding to

## Why Bazel?

DevFeed: [Why Bazel?](<https://devfeed.tech/articles/why-bazel-21770.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/creating-a-blog-with-bazel/03-why-bazel/>)

Author: Marc Plano-Lesay

Published: 2019-11-02T07:00:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [bazel](<https://devfeed.tech/topics/bazel.md>), [Caching](<https://devfeed.tech/topics/caching.md>), [toolchain](<https://devfeed.tech/topics/toolchain.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>)

Tags: [bazel](<https://devfeed.tech/tags/bazel.md>), [build-system](<https://devfeed.tech/tags/build-system.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [caching](<https://devfeed.tech/tags/caching.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [reproducibility](<https://devfeed.tech/tags/reproducibility.md>), [toolchain](<https://devfeed.tech/tags/toolchain.md>)

### AI overview

This tutorial explains what Bazel is, how its hermetic and reproducible build model works, and why the author chose it. It demonstrates C++ library and binary targets, dependency-driven builds, caching, toolchains, and extensibility through Starlark rules.

### Source excerpt

In this post, we'll cover what Bazel is, how to use it, and why I chose to use it. What is Bazel? Bazel is a build-system released by Google in 2015. It actually is derived from the internal build-system Google uses internally for most of its own code-base, called Blaze. Building at scale Bazel has a huge focus on hermetic builds, and reproducibility. Every build step is, from a really broad perspective, defined as a list of inputs, tools, and outputs. This allows for efficient and robust caching (if no inputs nor tools changed, then this target doesn't need to be rebuilt, and this cascades through the whole build graph). Let's see a sample definition of a C++ library, as well as a C++ binary depending on it: BUILD cc_library( name = "my_feature" srcs = [ "feature_impl.cpp", "utils.cpp", ], hdrs = [ "feature.hpp", "utils.hpp", ], ) cc_binary( name = "my_app", srcs = ["main.cpp"], deps = [ ":my_feature", ], ) cc_library and cc_binary are both depending an implicit dependency on a C++ toolchain (I won't enter into any language-specific features in this post, but if you don't tell Bazel to use a specific C++ toolchain, it will try to use your system compiler - which is convenient, but loses a bit of hermeticity and reproducibility). Everything else is pretty obvious here: we defined two different build targets, one of them being a library called my_feature, and the other one a binary called my_app, depending on my_feature. If we build my_app, Bazel will automatically build my_feature first as you would expect, and then proceed to build my_app. If you change the main.cpp and re-build my_app, it will skip the compilation of my_feature entirely, as nothing changed. Bazel's cache handling is really reliable. During the past few months, I've done a lot of diverse things (writing my own rules, compiling a bunch of different languages, depending on third-party libraries and rules...), and never had a single time to run bazel clean. Now I didn't use a lot of other build systems

## Rebuilding a Blog with Hugo and Bazel

DevFeed: [Rebuilding a Blog with Hugo and Bazel](<https://devfeed.tech/articles/a-new-beginning-21768.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/creating-a-blog-with-bazel/01-a-new-beginning/>)

Author: Marc Plano-Lesay

Published: 2019-10-31T10:05:00Z

Content type: article

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [bazel](<https://devfeed.tech/topics/bazel.md>), [Hugo](<https://devfeed.tech/topics/hugo.md>), [Deployment](<https://devfeed.tech/topics/deployment.md>), [Markdown](<https://devfeed.tech/topics/markdown.md>), [Docker](<https://devfeed.tech/topics/docker.md>), [HTML](<https://devfeed.tech/topics/html.md>)

Tags: [bazel](<https://devfeed.tech/tags/bazel.md>), [deployment](<https://devfeed.tech/tags/deployment.md>), [docker-image](<https://devfeed.tech/tags/docker-image.md>), [html](<https://devfeed.tech/tags/html.md>), [hugo](<https://devfeed.tech/tags/hugo.md>), [markdown](<https://devfeed.tech/tags/markdown.md>)

### AI overview

The author revives a blog by migrating it from Octopress 2 to Hugo and using Bazel to automate Sass processing, HTML generation, Docker image creation, and testing. Deployment is not yet complete.

### Source excerpt

This blog has been inactive for a long time. I tried to at least post an article yearly, and next thing you know, two years and a half fly by... Halloween seemed like a good time to resurrect it. I wanted to start writing again recently, and faced an issue: this blog was using Octopress 2. Well, Octopress has apparently been dead for even longer than this blog. So I wanted to switch to another static generator. I found Hugo, which is actively maintained and ticked all the boxes I had, so that's what I settled for (sorry for the probable RSS feed mess - while I set up 301 redirects for the old articles, I guess this won't play nicely with any RSS reader. This is actually what prompted this article...) This could have been an hour worth of work - migrating the content (both Hugo and Octopress are using Markdown, so that part was really simple), finding or putting together a nice template, and call it a day. But how fun is that? Instead, I chose to go with the most complex (hence fun, right?) approach possible. And that was by using Bazel to do everything. Sass linting and pre-processing, HTML generation, generating a Docker image, deploying it... and with tests for a lot of things along the way. Today, the deployment part is still missing (I'm working on it), but everything else is pretty much ready. I plan to describe this whole journey soon, although I don't know exactly which form it will take yet - probably a series of small articles covering a specific aspect. In the meantime, welcome back on a brand-new blog!

## Compat libraries incompatibilities

DevFeed: [Compat libraries incompatibilities](<https://devfeed.tech/articles/compat-libraries-incompatibilities-21766.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/compat-libraries-incompatibilities/>)

Author: Marc Plano-Lesay

Published: 2017-05-06T17:52:26Z

Content type: article

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [SDKs](<https://devfeed.tech/topics/sdks.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [libraries](<https://devfeed.tech/tags/libraries.md>), [sdk](<https://devfeed.tech/tags/sdk.md>), [vector](<https://devfeed.tech/tags/vector.md>)

### AI overview

This article examines incompatibilities in Android compatibility libraries, focusing on animated vector drawables and limitations affecting animations on older Android API levels.

### Source excerpt

Compat libraries are great. They allow us to work with the newest Android APIs, without thinking (much) about your minimum API level. Instead of thousands of devices, you can reach billions. With nearly no changes in your code. But sometimes, they're not so great...

## Android Things: first look

DevFeed: [Android Things: first look](<https://devfeed.tech/articles/android-things-first-look-21764.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/android-things-first-look/>)

Author: Marc Plano-Lesay

Published: 2017-01-06T09:55:08Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Internet of things](<https://devfeed.tech/topics/iot.md>), [Hardware](<https://devfeed.tech/topics/hardware.md>), [Raspberry Pi](<https://devfeed.tech/topics/raspberry-pi.md>), [intel](<https://devfeed.tech/topics/intel.md>), [SDKs](<https://devfeed.tech/topics/sdks.md>), [API](<https://devfeed.tech/topics/api.md>), [Android Studio](<https://devfeed.tech/topics/android-studio.md>)

Tags: [adb](<https://devfeed.tech/tags/adb.md>), [android](<https://devfeed.tech/tags/android.md>), [android-studio](<https://devfeed.tech/tags/android-studio.md>), [framework](<https://devfeed.tech/tags/framework.md>), [gpio](<https://devfeed.tech/tags/gpio.md>), [hardware](<https://devfeed.tech/tags/hardware.md>), [i2c](<https://devfeed.tech/tags/i2c.md>), [intel](<https://devfeed.tech/tags/intel.md>), [iot](<https://devfeed.tech/tags/iot.md>), [optional](<https://devfeed.tech/tags/optional.md>), [preview](<https://devfeed.tech/tags/preview.md>), [pwm](<https://devfeed.tech/tags/pwm.md>), [raspberry-pi](<https://devfeed.tech/tags/raspberry-pi.md>), [sdk](<https://devfeed.tech/tags/sdk.md>), [spi](<https://devfeed.tech/tags/spi.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

This article introduces Android Things, an Android version for developing embedded IoT devices. It describes supported boards, the Peripheral I/O and User Driver APIs, limitations of the bundled Android system, optional displays, installation on physical hardware, and initial project setup with Android Studio and adb.

### Source excerpt

What is Android Things? Android Things is an alternative Android version, announced at Google I/O 2015, and released as a first developer preview in December 2016. Its purpose is to develop embedded IoT devices, with a known and widely documented Android ecosystem basis. It's currently running on three different boards: the Intel Edison, the NXP Pico i.MX6UL, and the Raspberry Pi 3. Some higher-end boards are coming soon. On the SDK side, Android Things comes with a specific support library to ease low-level hardware usage. It consists in two parts: the Peripheral I/O API, which supports GPIO, PWM, I2C, SPI and UART, and the User Driver API, which allows a developer to write a hardware-specific, high-level driver, to ease hardware reusability by injecting events into the Android framework. Other applications can in turn use those events without having to interact with the hardware directly. There's a downside: the bundled Android is not as complete as the one you can find on a phone. Most of the standard applications aren't installed (Calendar, Phone...), and standard content providers are absent too (MediaProvider, Dictionary...). Android Things supports displays, with the default Android UI toolkit. However, the display is a bit different from what you're used to seeing on an Android device: there's no notification bar, navigation bar or anything, the running application will use the full display. That is, if it uses it at all: displays are purely optional.

## Use Apache HTTP Client on Android SDK 23

DevFeed: [Use Apache HTTP Client on Android SDK 23](<https://devfeed.tech/articles/use-apache-http-client-on-android-sdk-23-21779.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/use-apache-http-client-on-android-sdk-23/>)

Author: Marc Plano-Lesay

Published: 2015-10-01T13:46:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [HTTP](<https://devfeed.tech/topics/http.md>), [SDKs](<https://devfeed.tech/topics/sdks.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [apache](<https://devfeed.tech/tags/apache.md>), [build-system](<https://devfeed.tech/tags/build-system.md>), [client-library](<https://devfeed.tech/tags/client-library.md>), [deprecated](<https://devfeed.tech/tags/deprecated.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [http](<https://devfeed.tech/tags/http.md>), [sdk](<https://devfeed.tech/tags/sdk.md>)

### AI overview

This tutorial explains why applications using the Apache HTTP Client no longer build with Android SDK 23: Google removed the library's compile-time stubs, although the corresponding classes remained on Android 6 devices. It describes restoring the stubs through the Android build tools or directly using the provided JAR, while recommending migration to alternatives such as HttpURLConnection, OkHttp, or Ion.

### Source excerpt

With the Android M SDK (API 23), Google removed the Apache HTTP Client library. It was deprecated since API 22, and Google recommended to use HttpURLConnection instead since API 9. While the classes are still bundled in Android 6 ROMs, it won't be long until we see them completely go away. Some applications are still relying on this library, and need to be updated to use the SDK 23, without having time/budget/whatever required to switch from HTTP Client. While I strongly recommend you to still take time to move to something else (there are many high-level libraries, like OkHttp or Ion, or you can use HttpURLConnection to keep a low-level access), there is a way to use the Apache library while using the SDK 23.

## Share code across multiple platforms

DevFeed: [Share code across multiple platforms](<https://devfeed.tech/articles/share-code-across-multiple-platforms-21778.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/share-code-across-multiple-platforms/>)

Author: Marc Plano-Lesay

Published: 2015-06-11T13:33:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [cross-platform](<https://devfeed.tech/topics/cross-platform.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Code](<https://devfeed.tech/topics/code.md>), [Java](<https://devfeed.tech/topics/java.md>), [Objective-C](<https://devfeed.tech/topics/objective-c.md>), [Cordova](<https://devfeed.tech/topics/cordova.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [code](<https://devfeed.tech/tags/code.md>), [cross-platform](<https://devfeed.tech/tags/cross-platform.md>), [ios](<https://devfeed.tech/tags/ios.md>), [java](<https://devfeed.tech/tags/java.md>), [objective-c](<https://devfeed.tech/tags/objective-c.md>), [platforms](<https://devfeed.tech/tags/platforms.md>), [tools](<https://devfeed.tech/tags/tools.md>)

### AI overview

A tutorial on sharing application logic across multiple platforms by writing reusable C++ code and connecting it to platform-specific interfaces. It explains the trade-offs of cross-platform tools, introduces Java Native Interface (JNI), and shows how SWIG can generate wrapper code for Java integration.

### Source excerpt

When writing an application, you probably want it to run on most platforms possible. Having a game on Android is great, but what about this weird friend with his iPhone? It would be nice to be able to play with him. Of course there are cross-platforms technologies like Cordova or Titanium. But sadly, you can't achieve both a perfect user experience and great performances with this kind of tools. And even if you could: what about reusing code on the back-end? We need to share some code.

## RecyclerView basics

DevFeed: [RecyclerView basics](<https://devfeed.tech/articles/recyclerview-basics-21776.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/recyclerview-basics/>)

Author: Marc Plano-Lesay

Published: 2015-01-18T18:37:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [API](<https://devfeed.tech/topics/api.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [api](<https://devfeed.tech/tags/api.md>), [collection](<https://devfeed.tech/tags/collection.md>), [components](<https://devfeed.tech/tags/components.md>), [java](<https://devfeed.tech/tags/java.md>), [layout](<https://devfeed.tech/tags/layout.md>), [list](<https://devfeed.tech/tags/list.md>), [recyclerview](<https://devfeed.tech/tags/recyclerview.md>), [support](<https://devfeed.tech/tags/support.md>)

### AI overview

This tutorial introduces Android RecyclerView, explaining how it recycles hidden item views and separates list behavior into components such as the adapter, layout manager, view holder, and RecyclerView itself. It then outlines a basic Java implementation using a collection of items, Gradle dependencies, and a linear layout.

### Source excerpt

Introduction to RecyclerView RecyclerView has been introduced with Android 5, in the support-v7 package. It allows to display a collection of items in an arbitrary disposition (think of a ListView, but much more flexible). As the name of the support package indicates, it's available from the API level 7 (Android 2.1). Its name comes from the way it works: when an item is hidden, instead of being destroyed and a new one being created for each newly displayed item, hidden ones are recycled: they are reused, with new data bound on them.

## Hosting different kinds of apps on nginx

DevFeed: [Hosting different kinds of apps on nginx](<https://devfeed.tech/articles/hosting-different-kinds-of-apps-on-nginx-21772.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/hosting-different-kinds-of-apps-on-nginx/>)

Author: Marc Plano-Lesay

Published: 2014-10-15T08:55:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [nginx](<https://devfeed.tech/topics/nginx.md>), [hosting](<https://devfeed.tech/topics/hosting.md>), [PHP](<https://devfeed.tech/topics/php.md>), [Ruby on Rails](<https://devfeed.tech/topics/ruby-on-rails.md>), [SSL](<https://devfeed.tech/topics/ssl.md>), [Arch Linux](<https://devfeed.tech/topics/archlinux.md>)

Tags: [hosting](<https://devfeed.tech/tags/hosting.md>), [nginx](<https://devfeed.tech/tags/nginx.md>), [php](<https://devfeed.tech/tags/php.md>), [ruby-on-rails](<https://devfeed.tech/tags/ruby-on-rails.md>), [ssl](<https://devfeed.tech/tags/ssl.md>), [web](<https://devfeed.tech/tags/web.md>)

### AI overview

A tutorial on configuring Nginx to host static HTML pages, PHP applications, Ruby on Rails or other Rack-based applications, and proxied web servers. It describes virtual-host organization and optional or required HTTPS behavior.

### Source excerpt

Engine what? Nginx (engine-x) is a web server and reverse proxy for web and mail protocols (HTTP, HTTPS, SMTP, POP3 and IMAP). It has been first released in 2004, and its usage keeps growing ever since (according to Netcraft, it was hosting 14.47% of active sites in August 2014). It's capable of hosting many kinds of applications: static HTML pages PHP, using PHP-FPM Ruby on Rails and any kind of Rack-based Ruby application, using Phusion Passenger proxying requests to another webserver (e.g. a software launching its own web server, like Kodi)

## Using an API - Trakt.tv example

DevFeed: [Using an API - Trakt.tv example](<https://devfeed.tech/articles/using-an-api-trakt-tv-example-21780.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/using-an-api-trakt-dot-tv-example/>)

Author: Marc Plano-Lesay

Published: 2014-10-08T22:06:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [API](<https://devfeed.tech/topics/api.md>), [Ruby](<https://devfeed.tech/topics/ruby.md>), [JSON](<https://devfeed.tech/topics/json.md>), [Code](<https://devfeed.tech/topics/code.md>), [Programming](<https://devfeed.tech/topics/programming.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [api-architecture](<https://devfeed.tech/tags/api-architecture.md>), [article](<https://devfeed.tech/tags/article.md>), [code](<https://devfeed.tech/tags/code.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [json](<https://devfeed.tech/tags/json.md>), [rest](<https://devfeed.tech/tags/rest.md>), [ruby](<https://devfeed.tech/tags/ruby.md>)

### AI overview

This tutorial explains how applications can use website data through APIs, using Trakt.tv as an example. It introduces clients and servers, XML and JSON data formats, and REST concepts, with Ruby code for sending requests.

### Source excerpt

A lot of websites are generating data which could be really useful outside a web browser. Having the weather shown on your smartphone's lock-screen, the delay until your next bus... How can we use this from an application? This article will explain what's behind these hidden data flows, and how to use them. For this purpose, I'll use Trakt.tv as an example. If you don't know it: Trakt allows you to manage your movie/TV series library, keep track of watch progress, your ratings, comments... and see those of other people. Some code will show how to send such requests. It will be written in Ruby.

## Compile FFmpeg for Android

DevFeed: [Compile FFmpeg for Android](<https://devfeed.tech/articles/compile-ffmpeg-for-android-21767.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/compile-ffmpeg-for-android/>)

Author: Marc Plano-Lesay

Published: 2014-06-20T08:40:00Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [FFmpeg (Fast Forward Moving Picture Experts Group)](<https://devfeed.tech/topics/ffmpeg.md>), [Android](<https://devfeed.tech/topics/android.md>), [C](<https://devfeed.tech/topics/c.md>), [Linux](<https://devfeed.tech/topics/linux.md>), [Open Source](<https://devfeed.tech/topics/open-source.md>), [Stack Overflow](<https://devfeed.tech/topics/stackoverflow.md>), [GitHub](<https://devfeed.tech/topics/github.md>)

Tags: [2](<https://devfeed.tech/tags/2.md>), [android](<https://devfeed.tech/tags/android.md>), [build](<https://devfeed.tech/tags/build.md>), [c](<https://devfeed.tech/tags/c.md>), [ffmpeg](<https://devfeed.tech/tags/ffmpeg.md>), [github](<https://devfeed.tech/tags/github.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [linux](<https://devfeed.tech/tags/linux.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [sdk](<https://devfeed.tech/tags/sdk.md>), [software](<https://devfeed.tech/tags/software.md>), [source](<https://devfeed.tech/tags/source.md>)

### AI overview

A tutorial explains how to compile FFmpeg 2.2.3 for Android using the Android SDK and NDK, with steps for Linux, third-party libraries, an NDK module, and JNI wrappers in C and Java.

### Source excerpt

When you have to manipulate audio or video on Android, being used to open-source software, you have a single name which comes directly to you: FFmpeg. However, FFmpeg is a C software, meant to be used as an executable, and not officially supporting Android. There are a lot of partial and/or out-of-date how-to out there on how to get FFmpeg running on Android, like halfninja's build. However, I needed to use FFmpeg concat demuxer, introduced in FFmpeg 1.1. Most builds target 0.9. There's a ton of questions on StackOverflow about getting newer FFmpeg releases working on Android. So, here's a full explanation to get FFmpeg 2.2.3 "Muybridge" working on Android. I'll describe the steps for Linux, but everything is pretty standard shell and should work on any decent OS.

## Building a Debounced Keyboard with an Arduino Leonardo

DevFeed: [Building a Debounced Keyboard with an Arduino Leonardo](<https://devfeed.tech/articles/arduino-leonardo-fully-featured-keyboard-21765.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/arduino-leonardo-fully-featured-keyboard/>)

Author: Marc Plano-Lesay

Published: 2014-05-04T21:03:16Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Arduino](<https://devfeed.tech/topics/arduino.md>), [Code](<https://devfeed.tech/topics/code.md>), [API](<https://devfeed.tech/topics/api.md>)

Tags: [arduino](<https://devfeed.tech/tags/arduino.md>), [arrays](<https://devfeed.tech/tags/arrays.md>), [circuit](<https://devfeed.tech/tags/circuit.md>), [functional](<https://devfeed.tech/tags/functional.md>), [github](<https://devfeed.tech/tags/github.md>), [keyboard](<https://devfeed.tech/tags/keyboard.md>), [state](<https://devfeed.tech/tags/state.md>), [stateful](<https://devfeed.tech/tags/stateful.md>)

### AI overview

This tutorial explains how to use an Arduino Leonardo to emulate a keyboard with a joystick and arcade buttons. It develops the solution from a basic keyboard implementation to state tracking and button debouncing, while noting that the debounce delay may need adjustment for different buttons.

### Source excerpt

The Leonardo has a simple keyboard API. I needed a way to emulate a keyboard (from a joystick and arcade buttons - you see where I'm going now). Here's how I did it.

## Android: display a Dialog from an AppWidget

DevFeed: [Android: display a Dialog from an AppWidget](<https://devfeed.tech/articles/android-display-a-dialog-from-an-appwidget-21763.md>)

Original publisher: [Read original article](<https://enoent.fr/posts/android-display-a-dialog-from-an-appwidget/>)

Author: Marc Plano-Lesay

Published: 2014-04-06T20:27:19Z

Content type: tutorial

Language: en

Sources: [Marc Plano-Lesay](<https://devfeed.tech/sources/marc-plano-lesay.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [App](<https://devfeed.tech/topics/app.md>), [Code](<https://devfeed.tech/topics/code.md>), [dialog](<https://devfeed.tech/topics/dialog.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [api](<https://devfeed.tech/tags/api.md>), [app](<https://devfeed.tech/tags/app.md>), [code](<https://devfeed.tech/tags/code.md>), [context](<https://devfeed.tech/tags/context.md>), [dialog](<https://devfeed.tech/tags/dialog.md>), [github](<https://devfeed.tech/tags/github.md>), [widget](<https://devfeed.tech/tags/widget.md>)

### AI overview

This tutorial explains how to display an Android dialog from an AppWidget by launching an activity with an activity context. It covers making the activity transparent and hiding it from history and recent apps, applying an appropriate dialog theme, reusing the activity for multiple dialogs, and finishing it when dialogs are dismissed.

### Source excerpt

Issue When you want to display a dialog, you don't only need a context, you need an activity context. From an activity, displaying a dialog is pretty straightforward: Display a dialog from an activity new AlertDialog.Builder(MyActivity.this) .setTitle("Dialog title") .setMessage("Dialog message") .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // Handle a positive answer } }) .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // Handle a negative answer } }) .setIcon(R.drawable.ic_dialog_alert) .show(); Okay, that's a pretty usual code sample. But what about displaying it from an app-widget?