Skip to content

Commit

Permalink
Implemented boards
Browse files Browse the repository at this point in the history
  • Loading branch information
rakeshpai committed Jul 27, 2017
1 parent 845bff2 commit e33f553
Show file tree
Hide file tree
Showing 16 changed files with 181 additions and 82 deletions.
18 changes: 18 additions & 0 deletions src/components/BoardPicker.js
@@ -0,0 +1,18 @@
import React from 'react';
import { boards } from '../lib/constants';

export default ({ filter=()=>{}, recommended, value, ...props }) => {
const filteredBoards = boards.filter(filter);

return (
<select {...props} value={value || ''}>
{!filteredBoards.some(b => b.id === value) && <option>Pick one...</option>}
{filteredBoards.map(board => (
<option key={board.id} value={board.id}>
{board.name}
{board.id === recommended && ' (recommended)'}
</option>
))}
</select>
)
};
11 changes: 11 additions & 0 deletions src/components/Gateway.js
Expand Up @@ -13,6 +13,7 @@ import { RightAlignedLabel, InlineLabel } from './FormLabels';
import { Checkbox, RadioButton } from './FormControls';
import { NavPage, ColumnContainer, LeftColumn, RightColumn } from './Layouts';
import PageMenu from './PageMenu';
import BoardPicker from './BoardPicker';
import { Form as NodeForm } from './Node';
import HelpFooter from './HelpFooter';
import NotFound from './NotFound';
Expand Down Expand Up @@ -124,6 +125,16 @@ export default props => {
<GatewayTypePicker selectedGatewayType={gateway.gatewayType}
onGatewayTypeChange={e => handlers.setType(e.target.value)} />

<RightAlignedLabel label='Board'>
<BoardPicker filter={b => b.chip === (gateway.gatewayType === 'esp8266' ? 'esp8266' : 'atmega328')}
value={gateway.board}
recommended={gateway.gatewayType === 'esp8266' ? 'd1_mini' : 'pro8MHzatmega328'}
onChange={e => handlers.setBoard(e.target.value)} />
<p className={info}>
Pick the board that you are basing the node on.
</p>
</RightAlignedLabel>


{['esp8266', 'ethernet'].includes(gateway.gatewayType) && (
<div>
Expand Down
32 changes: 23 additions & 9 deletions src/components/Node.js
Expand Up @@ -12,27 +12,42 @@ import Sensor from './Sensor';
import SensorPicker from './SensorPicker';
import TimeInput from './TimeInput';
import { Button } from './Buttons';
import BoardPicker from './BoardPicker';

import { css } from 'glamor';
import { pageHeading, pageSubheading, subheading } from '../styles/typography';
import { info } from '../styles/forms';

export const Form = ({ network, node, handlers }) => {
let addSensorDropdown;
const chip = (node.type === 'gateway' && node.gatewayType === 'esp8266') ? 'esp8266' : 'atmega328';

return (
<ColumnContainer>
<LeftColumn>
<div>
{node.type !== 'gateway' && (
<RightAlignedLabel label='Name this node'>
<input type='text' value={node.name}
onChange={e => handlers.setName(e.target.value)} />
<p className={info}>
Example: 'MotionSensor', or 'GardenLights'
</p>
</RightAlignedLabel>
<div>
<RightAlignedLabel label='Name this node'>
<input type='text' value={node.name}
onChange={e => handlers.setName(e.target.value)} />
<p className={info}>
Example: 'MotionSensor', or 'GardenLights'
</p>
</RightAlignedLabel>

<RightAlignedLabel label='Board'>
<BoardPicker filter={b => b.chip === chip}
value={node.board}
recommended='pro8MHzatmega328'
onChange={e => handlers.setBoard(e.target.value)} />
<p className={info}>
Pick the board that you are basing the node on.
</p>
</RightAlignedLabel>
</div>
)}

{network.radio === 'NRF24L01+' && (
<InlineLabel
label={'This node uses the NRF24L01+ PA+LNA module with a good power supply.'}
Expand Down Expand Up @@ -77,8 +92,7 @@ export const Form = ({ network, node, handlers }) => {
<ul className={css({marginBottom: 10, listStyle: 'none', padding: 0})}>
{node.sensors.map((sensor, sensorIndex) => (
<li key={sensorIndex}>
<Sensor sensorIndex={sensorIndex} nodeSleeps={node.battery.powered}
sensor={sensor} handlers={handlers} />
<Sensor {...{ node, sensorIndex, sensor, handlers }} />
</li>
))}
</ul>
Expand Down
10 changes: 5 additions & 5 deletions src/components/Pins.js
@@ -1,13 +1,13 @@
import React from 'react';
import { analogPins, digitalPins, pwmPins, interruptPins } from '../lib/constants';
import { chips } from '../lib/constants';

const Dropdown = ({pinList, ...props}) => (
<select {...props}>
{pinList.map(p => <option value={p} key={p}>{p}</option>)}
</select>
);

export const AnalogPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={analogPins[chip]} {...props} />;
export const DigitalPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={digitalPins[chip]} {...props} />;
export const PWMPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={pwmPins[chip]} {...props} />;
export const InterruptPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={interruptPins[chip]} {...props} />;
export const AnalogPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={chips[chip].pins.analog} {...props} />;
export const DigitalPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={chips[chip].pins.digital} {...props} />;
export const PWMPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={chips[chip].pins.pwm} {...props} />;
export const InterruptPins = ({ chip = 'atmega328', ...props }) => <Dropdown pinList={chips[chip].pins.interrupt} {...props} />;
12 changes: 6 additions & 6 deletions src/components/Sensor.js
Expand Up @@ -10,7 +10,7 @@ import { Checkbox } from './FormControls';
import TimeInput from './TimeInput';
import { confirm } from './Modal';

import { sensors, sensorsByType } from '../lib/constants';
import { sensors, sensorsByType, boardsById } from '../lib/constants';

const styles = {
container: css({
Expand All @@ -36,7 +36,7 @@ const styles = {
})
};

export default ({ sensor, sensorIndex, handlers, nodeSleeps }) => {
export default ({ node, sensor, sensorIndex, handlers }) => {
const sensorHandlers = handlers.sensorHandlers(sensorIndex);

const pinProps = { value: sensor.pin, onChange: e => sensorHandlers.setPin(e.target.value) };
Expand All @@ -55,13 +55,13 @@ export default ({ sensor, sensorIndex, handlers, nodeSleeps }) => {

{(sensorsByType[sensor.type].pinType === 'analog') && (
<RightAlignedLabel label='Sense pin'>
<AnalogPins {...pinProps} />
<AnalogPins {...pinProps} chip={boardsById[node.board || 'pro8MHzatmega328'].chip} />
</RightAlignedLabel>
)}

{(['relay', 'latchingRelay', 'digitalOutput'].includes(sensor.type)) && (
<RightAlignedLabel label='Output pin'>
<DigitalPins {...pinProps} />
<DigitalPins {...pinProps} chip={boardsById[node.board || 'pro8MHzatmega328'].chip} />
</RightAlignedLabel>
)}

Expand All @@ -72,7 +72,7 @@ export default ({ sensor, sensorIndex, handlers, nodeSleeps }) => {
.includes(sensor.type)
&& (
<RightAlignedLabel label='Sense pin'>
<InterruptPins {...pinProps} />
<InterruptPins {...pinProps} chip={boardsById[node.board || 'pro8MHzatmega328'].chip} />
</RightAlignedLabel>
)
}
Expand All @@ -86,7 +86,7 @@ export default ({ sensor, sensorIndex, handlers, nodeSleeps }) => {
onUnitChange={e => sensorHandlers.setReportIntervalUnit(e.target.value)}
/>

{nodeSleeps && (
{node.battery.powered && (
<p className={info}>
If the node is asleep at this time, the value will be reported
the next time the node wakes up.
Expand Down
1 change: 1 addition & 0 deletions src/containers/Node.js
Expand Up @@ -18,6 +18,7 @@ export const createHandlers = dispatch => (networkId, nodeId) => {
deleteNode: _ => { d('DELETE'); dispatch(push(`/networks/${networkId}`)); },

setName: name => d('SET_NAME', { name }),
setBoard: board => d('SET_BOARD', { board }),
setDeviceKey: key => d('SET_DEVICE_KEY', { key }),
setPA: pa => d('SET_PA', { pa }),
setHW: hw => d('SET_HW', { hw }),
Expand Down
73 changes: 56 additions & 17 deletions src/lib/constants.js
Expand Up @@ -53,25 +53,64 @@ export const nmFiles = ([
{ key: 'nm-h', name: 'NodeManager.h' }
]).map(f => ({ ...f, path: 'https://raw.githubusercontent.com/mysensors/NodeManager/master/' }));

export const analogPins = {
atmega328: Array(8).fill(0).map((_, i) => `A${i}`),
esp8266: [ 'A0' ]
};

export const digitalPins = {
atmega328: [ ...Array(14).fill(0).map((_, i) => `D${i}`), ...analogPins.atmega328 ],
esp8266: [ 0,1,2,3,4,5,12,13,14,15,16 ].map(i => `D${i}`)
};
export const chips = {
atmega328: {
platform: 'atmelavr',
pins: {
analog: Array(8).fill(0).map((_, i) => `A${i}`),
digital: [
...Array(14).fill(0).map((_, i) => `D${i}`),
...Array(8).fill(0).map((_, i) => `A${i}`) // all analog pins
],
pwm: [ 3,5,6,10,11 ].map(i => `D${i}`),
interrupt: [ 'D2', 'D3' ]
}
},
esp8266: {
platform: 'espressif8266',
pins: {
analog: [ 'A0' ],
digital: [ 0,1,2,3,4,5,12,13,14,15,16 ].map(i => `D${i}`),
pwm: [ 0,1,2,3,4,5,12,13,14,15,16 ].map(i => `D${i}`), // all digital pins
interrupt: [ 0,1,2,3,4,5,12,13,14,15 ].map(i => `D${i}`) // all except D16
}
}
}

export const pwmPins = {
atmega328: [ 3,5,6,10,11 ].map(i => `D${i}`),
esp8266: [ ...digitalPins.esp8266 ]
};
export const boards = [
{
id: 'pro8MHzatmega328',
name: 'Arduino Pro Mini 3.3v',
chip: 'atmega328'
},
{
id: 'pro16MHzatmega328',
name: 'Arduino Pro Mini 5v',
chip: 'atmega328'
},
{
id: 'nanoatmega328',
name: 'Arduino Nano',
chip: 'atmega328'
},
{
id: 'uno',
name: 'Arduino Uno',
chip: 'atmega328'
},
{
id: 'nodemcuv2',
name: 'NodeMCU 1.0 (ESP-12E Module)',
chip: 'esp8266'
},
{
id: 'd1_mini',
name: 'Wemos D1 mini',
chip: 'esp8266'
}
];

export const interruptPins = {
atmega328: [ 'D2', 'D3' ],
esp8266: [ ...digitalPins.esp8266.filter(p => p !== 'D16') ]
};
export const boardsById = boards.reduce((acc, board) => ({ ...acc, [board.id]: board }), {});

export const sensors = [
{
Expand Down
6 changes: 3 additions & 3 deletions src/lib/validate-network.js
@@ -1,4 +1,4 @@
import { radios, sensors, analogPins, digitalPins } from './constants';
import { radios, sensors, chips, digitalPins } from './constants';

const createExpect = record => (value, path) => {
const chainable = {
Expand Down Expand Up @@ -108,13 +108,13 @@ export default network => {
ex(sensor.type, 'type').toBeOfSet(sensors.map(s => s.type));

if(sensors.find(s => s.type === sensor.type).pinType === 'analog') {
ex(sensor.pin, 'pin').toBeOfSet(analogPins[chip]);
ex(sensor.pin, 'pin').toBeOfSet(chips[chip].pins.analog);

if('reverse' in sensor) ex(sensor.reverse, 'reverse').toBeA('boolean');
if('usePowerPin' in sensor) {
ex(sensor.usePowerPin, 'usePowerPin').toBeA('boolean');

if(sensor.usePowerPin) ex(sensor.powerPin, 'powerPin').toBeOfSet(digitalPins[chip]);
if(sensor.usePowerPin) ex(sensor.powerPin, 'powerPin').toBeOfSet(chips[chip].pins.digital);
}

if('reportPercentage' in sensor) {
Expand Down
10 changes: 9 additions & 1 deletion src/reducers/gateway.js
@@ -1,9 +1,17 @@
import { boardsById } from '../lib/constants';

export default (state, action) => {
// 'dm' is for deepModify, modifies a key under the state object.
const dm = (key, modified) => ({ ...state, [key]: { ...state[key], ...modified}});

switch(action.type.slice(('GATEWAY/').length)) {
case 'SET_TYPE': return { ...state, gatewayType: action.gatewayType };
case 'SET_TYPE': return {
...state,
gatewayType: action.gatewayType,
board: (state.board && action.gatewayType === 'esp8266' && boardsById[state.board].chip === 'esp8266')
? state.board
: (state.board && boardsById[state.board].chip === 'atmega328') ? state.board : null
};

case 'SET_DHCP': return dm('ethernet', { dhcp: action.dhcp });
case 'SET_IP': return dm('ethernet', { ip: action.ip });
Expand Down
18 changes: 18 additions & 0 deletions src/reducers/migrations.js
@@ -1,5 +1,23 @@
import { sensorsByType } from '../lib/constants';

const migrations = [
network => network, // Need this for seeding
network => ({
...network,
nodes: network.nodes.map(node => ({
...node,
board: (node.type === 'gateway' && node.gatewayType === 'esp8266') ? 'd1_mini' : 'pro8MHzatmega328',
sensors: node.sensors.map(sensor => {
if(sensorsByType[sensor.type].pinType !== 'analog') return sensor;

return {
...sensor,
reportInterval: sensor.reportInterval || 10,
reportIntervalUnit: sensor.reportIntervalUnit || 'minutes'
};
})
}))
})
];

export const migrate = network => {
Expand Down
1 change: 1 addition & 0 deletions src/reducers/networks.js
Expand Up @@ -6,6 +6,7 @@ import nodeReducer from './node';

const defaultNode = _ => ({
name: 'MyNode',
board: 'pro8MHzatmega328',
type: 'node',
key: generateHexNumber(18),
pa: false,
Expand Down
7 changes: 4 additions & 3 deletions src/reducers/node.js
@@ -1,4 +1,4 @@
import { sensorsByType, analogPins, digitalPins } from '../lib/constants';
import { sensorsByType, chips } from '../lib/constants';

const getNextAvailablePin = (type, node, ignore = []) => {
const pinType = sensorsByType[type].pinType;
Expand All @@ -10,7 +10,7 @@ const getNextAvailablePin = (type, node, ignore = []) => {
...ignore
];

return (pinType === 'analog' ? analogPins : digitalPins)[chip].find(p => !usedPins.includes(p));
return chips[chip].pins[pinType].find(p => !usedPins.includes(p));
}

const getPowerPin = (type, node) => {
Expand All @@ -19,7 +19,7 @@ const getPowerPin = (type, node) => {
if(usedPowerPins.length) return usedPowerPins[0];

const usedPins = node.sensors.map(s => s.pin);
return digitalPins[chip].find(p => !usedPins.includes(p));
return chips[chip].pins.digital.find(p => !usedPins.includes(p));
}

const defaultSensorValues = (sensorType, node) => {
Expand Down Expand Up @@ -63,6 +63,7 @@ export default (state, action) => {

switch(action.type.slice(('NODE/').length)) {
case 'SET_NAME': return m({ name: action.name });
case 'SET_BOARD': return m({ board: action.board });
case 'SET_DEVICE_KEY': return m({ key: action.key });
case 'SET_PA': return m({ pa: action.pa });
case 'SET_HW': return m({ hw: action.hw });
Expand Down
9 changes: 5 additions & 4 deletions src/sketch-generator/files-by-format.js
@@ -1,6 +1,7 @@
import { spFiles, nmFiles } from '../lib/constants';
import securityPersonalizer, { platformini as spPlatformini } from './security-personalizer';
import nodeSketchFiles, { platformini as nodePlatformini } from './node-sketch-files';
import securityPersonalizer from './security-personalizer';
import nodeSketchFiles from './node-sketch-files';
import platformioIni from './platformioini';

const fileContents = ({ key }) => JSON.parse(window.localStorage.getItem(key)).text;

Expand Down Expand Up @@ -64,7 +65,7 @@ export const platformio = nodeParams => {
})),
{
path: `${sketchName}/SecurityPersonalizer/platformio.ini`,
contents: spPlatformini()
contents: platformioIni(nodeParams)
},
...nmFiles.map(file => ({
path: `${sketchName}/${sketchName}/src/${file.name}`,
Expand All @@ -76,7 +77,7 @@ export const platformio = nodeParams => {
})),
{
path: `${sketchName}/${sketchName}/platformio.ini`,
contents: nodePlatformini(nodeParams)
contents: platformioIni(nodeParams)
}
]
};

0 comments on commit e33f553

Please sign in to comment.